diff --git a/9781430236238.jpg b/9781430236238.jpg new file mode 100644 index 0000000..14e2166 Binary files /dev/null and b/9781430236238.jpg differ diff --git a/Arduino Projects Save World/978-1-4302-3623-8_CH07/.DS_Store b/Arduino Projects Save World/978-1-4302-3623-8_CH07/.DS_Store new file mode 100644 index 0000000..baa2700 Binary files /dev/null and b/Arduino Projects Save World/978-1-4302-3623-8_CH07/.DS_Store differ diff --git a/Arduino Projects Save World/978-1-4302-3623-8_CH07/L7_1/_7_1.pde b/Arduino Projects Save World/978-1-4302-3623-8_CH07/L7_1/_7_1.pde new file mode 100644 index 0000000..e106864 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_CH07/L7_1/_7_1.pde @@ -0,0 +1,122 @@ +#include +LiquidCrystal lcd(3, 5, 6, 7, 8, 9); + +const int voltageSensor = A0; +const int currentSensor = A1; + +const int numberOfSamples = 3000; + +// Calibration constants +const float AC_WALL_VOLTAGE = 120.9; +const float AC_ADAPTER_VOLTAGE = 14.1; +const float AC_VOLTAGE_DIV_VOUT = 0.85; +const float CT_BURDEN_RESISTOR = 40.2; +const float CT_TURNS = 2280.0; + +// Calibration coefficients +const float VCAL = 1.0; +const float ICAL = 1.0; +const float PHASECAL = 0.9; + +// Calculated ratio constants, modified by VCAL/ICAL +const float AC_ADAPTER_RATIO = AC_WALL_VOLTAGE / AC_ADAPTER_VOLTAGE; +const float AC_VOLTAGE_DIV_RATIO = AC_ADAPTER_VOLTAGE / AC_VOLTAGE_DIV_VOUT; +const float V_RATIO = AC_ADAPTER_RATIO * AC_VOLTAGE_DIV_RATIO * 5 / 1024 * VCAL; +const float I_RATIO = CT_TURNS / CT_BURDEN_RESISTOR * 5 / 1024 * ICAL; + +// Sample variables +int lastSampleV, lastSampleI, sampleV, sampleI; + +// Filter variables +float lastFilteredV, lastFilteredI, filteredV, filteredI; + +// Power sample totals +float sumI, sumV, sumP; + +// Phase calibrated instantaneous voltage +float calibratedV; + +// Calculated power variables +float realPower, apparentPower, powerFactor, voltageRMS, currentRMS; +unsigned long last_kWhTime, kWhTime; +float kilowattHour = 0.0; + +void setup() { + lcd.begin(16,2); +} + +void loop() { + calculatePower(); + displayPower(); +} + +void calculatePower() { + for (int i = 0; i < numberOfSamples; i++) { + // Used for voltage offset removal + lastSampleV = sampleV; + lastSampleI = sampleI; + + // Read voltage and current values + sampleV = analogRead(voltageSensor); + sampleI = analogRead(currentSensor); + + // Used for voltage offset removal + lastFilteredV = filteredV; + lastFilteredI = filteredI; + + // Digital high pass filters to remove 2.5V DC offset + filteredV = 0.996 * (lastFilteredV + sampleV - lastSampleV); + filteredI = 0.996 * (lastFilteredI + sampleI - lastSampleI); + + // Phase calibration + calibratedV = lastFilteredV + PHASECAL * (filteredV - lastFilteredV); + + // Root-mean-square voltage + sumV += calibratedV * calibratedV; + + // Root-mean-square current + sumI += filteredI * filteredI; + + // Instantaneous Power + sumP += abs(calibratedV * filteredI); + } + + // Calculation of the root of the mean of the voltage and current squared (rms) + // Calibration coeficients applied + voltageRMS = V_RATIO * sqrt(sumV / numberOfSamples); + currentRMS = I_RATIO * sqrt(sumI / numberOfSamples); + + // Calculate power values + realPower = V_RATIO * I_RATIO * sumP / numberOfSamples; + apparentPower = voltageRMS * currentRMS; + powerFactor = realPower / apparentPower; + + // Calculate running total kilowatt hours + // This value will reset in 50 days + last_kWhTime = kWhTime; + kWhTime = millis(); + // Convert watts into kilowatts and multiply by the time since the last reading in ms + kilowattHour += (realPower / 1000) * ((kWhTime - last_kWhTime) / 3600000.0); + + // Reset sample totals + sumV = 0; + sumI = 0; + sumP = 0; +} + +void displayPower() { + lcd.clear(); + lcd.print(realPower, 0); + lcd.print("w "); + lcd.print(apparentPower, 0); + lcd.print("va "); + lcd.print(powerFactor * 100, 0); + lcd.print("%"); + lcd.setCursor(0,1); + lcd.print(voltageRMS, 0); + lcd.print("v "); + lcd.print(currentRMS, 1); + lcd.print("a "); + lcd.print(kilowattHour, 4); +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_CH07/L7_2/_7_2.pde b/Arduino Projects Save World/978-1-4302-3623-8_CH07/L7_2/_7_2.pde new file mode 100644 index 0000000..5b440cf --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_CH07/L7_2/_7_2.pde @@ -0,0 +1,170 @@ +#include +#include + +LiquidCrystal lcd(3, 5, 6, 7, 8, 9); +File file; + +const int voltageSensor = A0; +const int currentSensor = A1; +const int SDcs = 4; + +const int numberOfSamples = 3000; + +// Calibration constants +const float AC_WALL_VOLTAGE = 120.9; +const float AC_ADAPTER_VOLTAGE = 14.1; +const float AC_VOLTAGE_DIV_VOUT = 0.85; +const float CT_BURDEN_RESISTOR = 40.2; +const float CT_TURNS = 2280.0; + +// Calibration coeficients +const float VCAL = 1.0; +const float ICAL = 1.0; +const float PHASECAL = 0.9; + +// Calculated ratio constants, modified by VCAL/ICAL +const float AC_ADAPTER_RATIO = AC_WALL_VOLTAGE / AC_ADAPTER_VOLTAGE; +const float AC_VOLTAGE_DIV_RATIO = AC_ADAPTER_VOLTAGE / AC_VOLTAGE_DIV_VOUT; +const float V_RATIO = AC_ADAPTER_RATIO * AC_VOLTAGE_DIV_RATIO * 5 / 1024 * VCAL; +const float I_RATIO = CT_TURNS / CT_BURDEN_RESISTOR * 5 / 1024 * ICAL; + +// Sample variables +int lastSampleV, lastSampleI, sampleV, sampleI; + +// Filter variables +float lastFilteredV, lastFilteredI, filteredV, filteredI; + +// Power sample totals +float sumI, sumV, sumP; + +// Phase calibrated instantaneous voltage +float calibratedV; + +// Calculated power variables +float realPower, apparentPower, powerFactor, voltageRMS, currentRMS; +unsigned long last_kWhTime, kWhTime; +float kilowattHour = 0.0; + +unsigned long startTime = 0; +unsigned long interval = 10000; + +void setup() { + lcd.begin(16,2); + Serial.begin(9600); + + // Starts the SD card + Serial.print("Initializing SD card..."); + pinMode(10, OUTPUT); + + // Checks that the SD card is present + if (!SD.begin(SDcs)) { + Serial.println("initialization failed!"); + return; + } + Serial.println("initialization done."); +} + +void loop() { + calculatePower(); + displayPower(); + + // Opens file on SD if interval has passed + if (startTime + interval < millis()) { + // Opens files and sets to write mode + file = SD.open("data.txt", FILE_WRITE); + + // Writes values to file if present + if (file) { + Serial.print("Writing to data.txt... "); + + file.print(realPower); + file.print(","); + file.print(apparentPower); + file.print(","); + file.print(powerFactor * 100); + file.print(","); + file.print(voltageRMS); + file.print(","); + file.print(currentRMS); + file.print(","); + file.println(kilowattHour); + + Serial.println("done."); + // Need to close a file to save the data + file.close(); + Serial.println("File closed."); + } else Serial.println("Error opening data.txt."); + startTime = millis(); + } +} + +void calculatePower() { + for (int i = 0; i < numberOfSamples; i++) { + // Used for voltage offset removal + lastSampleV = sampleV; + lastSampleI = sampleI; + + // Read voltage and current values + sampleV = analogRead(voltageSensor); + sampleI = analogRead(currentSensor); + + // Used for voltage offset removal + lastFilteredV = filteredV; + lastFilteredI = filteredI; + + // Digital high pass filters to remove 2.5V DC offset + filteredV = 0.996 * (lastFilteredV + sampleV - lastSampleV); + filteredI = 0.996 * (lastFilteredI + sampleI - lastSampleI); + + // Phase calibration + calibratedV = lastFilteredV + PHASECAL * (filteredV - lastFilteredV); + + // Root-mean-square voltage + sumV += calibratedV * calibratedV; + + // Root-mean-square current + sumI += filteredI * filteredI; + + // Instantaneous Power + sumP += abs(calibratedV * filteredI); + } + + // Calculation of the root of the mean of the voltage and current squared (rms) + // Calibration coeficients applied + voltageRMS = V_RATIO * sqrt(sumV / numberOfSamples); + currentRMS = I_RATIO * sqrt(sumI / numberOfSamples); + + // Calculate power values + realPower = V_RATIO * I_RATIO * sumP / numberOfSamples; + apparentPower = voltageRMS * currentRMS; + powerFactor = realPower / apparentPower; + + // Calculate running total kilowatt hours + // This value will reset in 50 days + last_kWhTime = kWhTime; + kWhTime = millis(); + // Convert watts into kilowatts and multiply by the time since the last reading + kilowattHour += (realPower / 1000) * ((kWhTime - last_kWhTime) / 3600000.0); + + // Reset sample totals + sumV = 0; + sumI = 0; + sumP = 0; +} + +void displayPower() { + lcd.clear(); + lcd.print(realPower, 0); + lcd.print("w "); + lcd.print(apparentPower, 0); + lcd.print("va "); + lcd.print(powerFactor * 100, 0); + lcd.print("%"); + lcd.setCursor(0,1); + lcd.print(voltageRMS, 0); + lcd.print("v "); + lcd.print(currentRMS, 1); + lcd.print("a "); + lcd.print(kilowattHour, 4); +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_CH07/__MACOSX/978-1-4302-3623-8_CH07/._.DS_Store b/Arduino Projects Save World/978-1-4302-3623-8_CH07/__MACOSX/978-1-4302-3623-8_CH07/._.DS_Store new file mode 100644 index 0000000..460d887 Binary files /dev/null and b/Arduino Projects Save World/978-1-4302-3623-8_CH07/__MACOSX/978-1-4302-3623-8_CH07/._.DS_Store differ diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch02 Spider Temps/CH2_1_one_temperature_probe/CH2_1_one_temperature_probe.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch02 Spider Temps/CH2_1_one_temperature_probe/CH2_1_one_temperature_probe.pde new file mode 100644 index 0000000..414b235 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch02 Spider Temps/CH2_1_one_temperature_probe/CH2_1_one_temperature_probe.pde @@ -0,0 +1,20 @@ +int TSensor = 0; // temperature sensor ADC input pin +int val = 0; // variable to store ADC value read +int TempOffset = 500; // value in mV when ambient is 0 degrees C +int TempCoef = 10; // Temperature coefficient mV per Degree C +float ADCmV = 4.8828; // mV per ADC increment (5 volts / 1024 increments) +float Temp = 0; // calculated temperature in C (accuraccy to two decimal places) + +void setup() +{ + Serial.begin(9600); // setup serial +} + +void loop() +{ + val = analogRead(TSensor); // read the input pin + Temp = ((val * ADCmV) - TempOffset) / TempCoef; // the ADC to C equation + Serial.println(Temp); // display in the SerialMonitor + delay (200); +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch02 Spider Temps/CH2_2_six_temperature_probe/CH2_2_six_temperature_probe.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch02 Spider Temps/CH2_2_six_temperature_probe/CH2_2_six_temperature_probe.pde new file mode 100644 index 0000000..a4c27c9 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch02 Spider Temps/CH2_2_six_temperature_probe/CH2_2_six_temperature_probe.pde @@ -0,0 +1,52 @@ +/* +SpiderTemps 6 sensor +Arduino projects to save the world + +This sketch reads all six analog inputs, calculates temperature(C) and outputs them to the serial monitor. +*/ + +int ADC0, ADC1, ADC2, ADC3, ADC4, ADC5; +int MCPoffset = 500; +int LM35offset = 0; + +void setup() { + Serial.begin(9600); +} + +void loop() { + getADC(); + float temp0 = calcTemp(ADC0, LM35offset); + float temp1 = calcTemp(ADC1, LM35offset); + float temp2 = calcTemp(ADC2, MCPoffset); + float temp3 = calcTemp(ADC3, MCPoffset); + float temp4 = calcTemp(ADC4, MCPoffset); + float temp5 = calcTemp(ADC5, MCPoffset); + + Serial.print(temp0, 0); + Serial.print(" "); + Serial.print(temp1, 0); + Serial.print(" "); + Serial.print(temp2, 0); + Serial.print(" "); + Serial.print(temp3, 0); + Serial.print(" "); + Serial.print(temp4, 0); + Serial.print(" "); + Serial.println(temp5, 0); + + delay(500); +} + +void getADC() { + ADC0 = analogRead(A0); + ADC1 = analogRead(A1); + ADC2 = analogRead(A2); + ADC3 = analogRead(A3); + ADC4 = analogRead(A4); + ADC5 = analogRead(A5); +} + +float calcTemp (int val, int offset) { + return ((val * 4.8828) - offset) / 10; +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch02 Spider Temps/CH2_3_six_temperature_probe_calibration/CH2_3_six_temperature_probe_calibration.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch02 Spider Temps/CH2_3_six_temperature_probe_calibration/CH2_3_six_temperature_probe_calibration.pde new file mode 100644 index 0000000..fccba38 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch02 Spider Temps/CH2_3_six_temperature_probe_calibration/CH2_3_six_temperature_probe_calibration.pde @@ -0,0 +1,61 @@ +/* +SpiderTemps 6 sensor plus software calibration +Arduino projects to save the world + +This sketch reads all six analog inputs, calculates temperature(C) and outputs them to the serial monitor. +*/ + +float temp0, temp1, temp2, temp3, temp4, temp5; +int ADC0, ADC1, ADC2, ADC3, ADC4, ADC5; +int MCPoffset = 500; +int LM35offset = 0; + +float calibration0 = 0; +float calibration1 = 0; +float calibration2 = 0; +float calibration3 = 0; +float calibration4 = 0; +float calibration5 = 0; + + +void setup() { + Serial.begin(9600); +} + +void loop() { + getADC(); + temp0 = calcTemp(ADC0, LM35offset, calibration0); + temp1 = calcTemp(ADC1, LM35offset, calibration1); + temp2 = calcTemp(ADC2, MCPoffset, calibration2); + temp3 = calcTemp(ADC3, MCPoffset, calibration3); + temp4 = calcTemp(ADC4, MCPoffset, calibration4); + temp5 = calcTemp(ADC5, MCPoffset, calibration5); + + Serial.print(temp0, 0); + Serial.print(" "); + Serial.print(temp1, 0); + Serial.print(" "); + Serial.print(temp2, 0); + Serial.print(" "); + Serial.print(temp3, 0); + Serial.print(" "); + Serial.print(temp4, 0); + Serial.print(" "); + Serial.println(temp5, 0); + + delay(500); +} + +void getADC() { + ADC0 = analogRead(A0); + ADC1 = analogRead(A1); + ADC2 = analogRead(A2); + ADC3 = analogRead(A3); + ADC4 = analogRead(A4); + ADC5 = analogRead(A5); +} + +float calcTemp (int val, int offset, float cal) { + return (((val * 4.8828) - offset) / 10) + cal; +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch02 Spider Temps/CH2_4_SpiderTemps_LCD/CH2_4_SpiderTemps_LCD.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch02 Spider Temps/CH2_4_SpiderTemps_LCD/CH2_4_SpiderTemps_LCD.pde new file mode 100644 index 0000000..0d5a58e --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch02 Spider Temps/CH2_4_SpiderTemps_LCD/CH2_4_SpiderTemps_LCD.pde @@ -0,0 +1,96 @@ +/* + SpiderTemps - LCD + Arduino projects to save the world + + This sketch reads all six analog inputs, calculates temperature + and outputs to the serial monitor. + It also displays them on an attached 20x2 LCD +*/ + +#include +//LCD pin setup +// (RS, Enable, D4, D5, D6, D7) +LiquidCrystal lcd(12, 11, 5, 4, 3, 2); + +// working variables +int ADC0, ADC1, ADC2, ADC3, ADC4, ADC5; +float temp0, temp1, temp2, temp3, temp4, temp5; + +// sensor offset constants +int MCPoffset = 500; +int LM35offset = 0; + +// sensor calibrations +int calibration0 = 0; +int calibration1 = 1; +int calibration2 = 0; +int calibration3 = 0; +int calibration4 = 0; +int calibration5 = 0; + + +void setup() { + Serial.begin(9600); + lcd.begin(20, 2); +} + +void loop() { + getADC(); + calcLoop(); + serialPrint(); + lcdPrint(); + delay(2000); +} + +void calcLoop(){ + temp0 = calcTemp(ADC0, MCPoffset, calibration0); + temp1 = calcTemp(ADC1, MCPoffset, calibration1); + temp2 = calcTemp(ADC2, MCPoffset, calibration2); + temp3 = calcTemp(ADC3, MCPoffset, calibration3); + temp4 = calcTemp(ADC4, MCPoffset, calibration4); + temp5 = calcTemp(ADC5, MCPoffset, calibration5); +} + +void getADC() { + ADC0 = analogRead(A0); + ADC1 = analogRead(A1); + ADC2 = analogRead(A2); + ADC3 = analogRead(A3); + ADC4 = analogRead(A4); + ADC5 = analogRead(A5); +} + +float calcTemp (int val, int offset, int cal) { + return (((val * 4.8828) - offset) / 10) + cal; +} + +void serialPrint(){ + Serial.print(temp0, 1); + Serial.print(" "); + Serial.print(temp1, 1); + Serial.print(" "); + Serial.print(temp2, 1); + Serial.print(" "); + Serial.print(temp3, 1); + Serial.print(" "); + Serial.print(temp4, 1); + Serial.print(" "); + Serial.println(temp5, 1); +} + +void lcdPrint(){ + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print(temp0, 1); + lcd.setCursor(7, 0); + lcd.print(temp1, 1); + lcd.setCursor(14, 0); + lcd.print(temp2, 1); + lcd.setCursor(0, 1); + lcd.print(temp3, 1); + lcd.setCursor(7, 1); + lcd.print(temp4, 1); + lcd.setCursor(14, 1); + lcd.print(temp5, 1); +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/CH3_1_Jungle_Power_sleeping_sensor/CH3_1_Jungle_Power_sleeping_sensor.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/CH3_1_Jungle_Power_sleeping_sensor/CH3_1_Jungle_Power_sleeping_sensor.pde new file mode 100644 index 0000000..317d55a --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/CH3_1_Jungle_Power_sleeping_sensor/CH3_1_Jungle_Power_sleeping_sensor.pde @@ -0,0 +1,112 @@ +/* + * sketch name : Rtc8564AttachInterruptSleep_Analogs + * summary : RTC8564で定周期タイマー割り込み & スリープ + * releases : 2011/3/15 + */ + +#include +#include +#include + +/* Project variables */ +int A0raw, A1raw, A2raw, A3raw; + + +/* RTC */ +#define RTC_SEC 0x00 // seconds +#define RTC_MIN 0x18 // minutes +#define RTC_HOUR 0x23 // hour in 24hr format +#define RTC_DAY 0x15 // day of the month +#define RTC_WEEK 0x02 // day of the week (00:Sunday – 06:Saturday) +#define RTC_MON 0x03 // month +#define RTC_YEAR 0x11 // year +byte date_time[7] = { + RTC_SEC + ,RTC_MIN + ,RTC_HOUR + ,RTC_DAY + ,RTC_WEEK + ,RTC_MON + ,RTC_YEAR +}; + +/* Check the power reset flag – this will decide if we should reset the clock or not */ +boolean init_flg = false; + +/* Measurement interval – how long do we want the Arduino to sleep? */ +#define RTC_INTERRUPT_TERM 10 + +/* What is the interval? 0:seconds, 1:minutes */ +#define RTC_INTERRUPT_MODE 0 + +/* Which pin is the clock interupt connected to? We only have a few options */ +#define RTC_INTERRUPT_PIN 2 + +void setup() { + Serial.begin(9600); + + // Date and Time initialization + Rtc.initDatetime(date_time); + + // RTC start + Rtc.begin(); + + // Check periodic interrupt time + if (!Rtc.isInterrupt()) { + + // if so, set interrupt + Rtc.syncInterrupt(RTC_INTERRUPT_MODE, RTC_INTERRUPT_TERM); + } + + // interrupt setting + pinMode(RTC_INTERRUPT_PIN, INPUT); + digitalWrite(RTC_INTERRUPT_PIN, HIGH); +} + +void loop() { + + // Upon waking up, we should check to see if there was a power event + if (init_flg) ReadRTC(); + init_flg = true; + + // stuff to do before sleep + // read the pins + A0raw = analogRead(0); + A1raw = analogRead(1); + A2raw = analogRead(2); + A3raw = analogRead(3); + // print it up + Serial.print(A0raw); + Serial.print(" : "); + Serial.print(A1raw); + Serial.print(" : "); + Serial.print(A2raw); + Serial.print(" : "); + Serial.println(A3raw); + Serial.println(); + + + // Sleep time! Dont put anything else in the main loop after this! + // Delay required to assure wake cleanly + delay(100); + SleepClass::powerDownAndWakeupExternalEvent(0); +} + +void ReadRTC() +{ + Rtc.available(); + Serial.print(0x2000 + Rtc.years(), HEX); + Serial.print("/"); + Serial.print(Rtc.months(), HEX); + Serial.print("/"); + Serial.print(Rtc.days(), HEX); + Serial.print(" "); + Serial.print(Rtc.hours(), HEX); + Serial.print(":"); + Serial.print(Rtc.minutes(), HEX); + Serial.print(":"); + Serial.print(Rtc.seconds(), HEX); + Serial.print(" "); + Serial.println((int)Rtc.weekdays()); +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/.DS_Store b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/.DS_Store differ diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/Rtc8564AttachInterrupt.cpp b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/Rtc8564AttachInterrupt.cpp new file mode 100644 index 0000000..0a23cc1 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/Rtc8564AttachInterrupt.cpp @@ -0,0 +1,242 @@ +extern "C" { + #include + #include + #include +} +#include +#include +#include "Rtc8564AttachInterrupt.h" + +#define RTC8564_SLAVE_ADRS (0xA2 >> 1) +#define BCD2Decimal(x) (((x>>4)*10)+(x&0xf)) + +// Constructors //////////////////////////////////////////////////////////////// + +Rtc8564AttachInterrupt::Rtc8564AttachInterrupt() + : _seconds(0), _minutes(0), _hours(0), _days(0), _weekdays(0), _months(0), _years(0), _century(0) +{ +} + +void Rtc8564AttachInterrupt::init(void) +{ + delay(1000); + Wire.beginTransmission(RTC8564_SLAVE_ADRS); + Wire.send(0x00); // write reg addr 00 + Wire.send(0x20); // 00 Control 1, STOP=1 + Wire.send(0x00); // 01 Control 2 + Wire.send(0x00); // 02 Seconds + Wire.send(0x00); // 03 Minutes + Wire.send(0x09); // 04 Hours + Wire.send(0x01); // 05 Days + Wire.send(0x01); // 06 Weekdays + Wire.send(0x01); // 07 Months + Wire.send(0x01); // 08 Years + Wire.send(0x00); // 09 Minutes Alarm + Wire.send(0x00); // 0A Hours Alarm + Wire.send(0x00); // 0B Days Alarm + Wire.send(0x00); // 0C Weekdays Alarm + Wire.send(0x00); // 0D CLKOUT + Wire.send(0x00); // 0E Timer control + Wire.send(0x00); // 0F Timer + Wire.send(0x00); // 00 Control 1, STOP=0 + Wire.endTransmission(); +} + +// Public Methods ////////////////////////////////////////////////////////////// + +void Rtc8564AttachInterrupt::begin(void) +{ + Wire.begin(); + if(isvalid() == false) { + + init(); + + if (isInitDatetime()) { + byte date_time[7]; + date_time[0] = _seconds; + date_time[1] = _minutes; + date_time[2] = _hours; + date_time[3] = _days; + date_time[4] = _weekdays; + date_time[5] = _months; + date_time[6] = _years; + sync(date_time); + } + } +} + +void Rtc8564AttachInterrupt::beginWithoutIsValid(void) +{ + Wire.begin(); + + init(); + + if (isInitDatetime()) { + byte date_time[7]; + date_time[0] = _seconds; + date_time[1] = _minutes; + date_time[2] = _hours; + date_time[3] = _days; + date_time[4] = _weekdays; + date_time[5] = _months; + date_time[6] = _years; + sync(date_time); + } +} + +void Rtc8564AttachInterrupt::initDatetime(uint8_t date_time[]) +{ + _seconds = (date_time[0]) ? date_time[0] : 0x00; + _minutes = (date_time[1]) ? date_time[1] : 0x00; + _hours = (date_time[2]) ? date_time[2] : 0x09; + _days = (date_time[3]) ? date_time[3] : 0x01; + _weekdays = (date_time[4]) ? date_time[4] : 0x01; + _months = (date_time[5]) ? date_time[5] : 0x01; + _years = (date_time[6]) ? date_time[6] : 0x01; +} + +bool Rtc8564AttachInterrupt::isInitDatetime(void) +{ + bool flg = false; + if ((_seconds & 0x00) != 0x00) flg = true; + if ((_minutes & 0x00) != 0x00) flg = true; + if ((_hours & 0x09) != 0x09) flg = true; + if ((_days & 0x01) != 0x01) flg = true; + if ((_weekdays & 0x01) != 0x01) flg = true; + if ((_months & 0x01) != 0x01) flg = true; + if ((_years & 0x01) != 0x01) flg = true; + return flg; +} + +void Rtc8564AttachInterrupt::sync(uint8_t date_time[],uint8_t size) +{ + Wire.beginTransmission(RTC8564_SLAVE_ADRS); + Wire.send(0x00); + Wire.send(0x20); + Wire.endTransmission(); + + Wire.beginTransmission(RTC8564_SLAVE_ADRS); + Wire.send(0x02); + Wire.send(date_time, size); + Wire.endTransmission(); + + Wire.beginTransmission(RTC8564_SLAVE_ADRS); + Wire.send(0x00); + Wire.send(0x00); + Wire.endTransmission(); +} + +void Rtc8564AttachInterrupt::syncInterrupt(unsigned int mode, unsigned long term) +{ + Wire.beginTransmission(RTC8564_SLAVE_ADRS); + Wire.send(0x01); + Wire.send(0x11); + Wire.endTransmission(); + + byte buf[2]; + if (mode == 1) { + buf[0] = 0x83; + } else { + buf[0] = 0x82; + } + buf[1] = term; + Wire.beginTransmission(RTC8564_SLAVE_ADRS); + Wire.send(0x0E); + Wire.send(buf, 2); + Wire.endTransmission(); +} + +bool Rtc8564AttachInterrupt::available(void) +{ + uint8_t buff[7]; + + Wire.beginTransmission(RTC8564_SLAVE_ADRS); + Wire.send(0x02); + Wire.endTransmission(); + + Wire.requestFrom(RTC8564_SLAVE_ADRS, 7); + + for(int i=0; i<7; i++){ + if(Wire.available()){ + buff[i] = Wire.receive(); + } + } + + _seconds = buff[0] & 0x7f; + _minutes = buff[1] & 0x7f; + _hours = buff[2] & 0x3f; + _days = buff[3] & 0x3f; + _weekdays = buff[4] & 0x07; + _months = buff[5] & 0x1f; + _years = buff[6]; + _century = (buff[5] & 0x80) ? 1 : 0; + return (buff[0] & 0x80 ? false : true); +} + +bool Rtc8564AttachInterrupt::isvalid(void) +{ + Wire.beginTransmission(RTC8564_SLAVE_ADRS); + Wire.send(0x02); + Wire.endTransmission(); + Wire.requestFrom(RTC8564_SLAVE_ADRS, 1); + if(Wire.available()){ + uint8_t buff = Wire.receive(); + return (buff & 0x80 ? false : true); + } + return false; +} + +bool Rtc8564AttachInterrupt::isInterrupt(void) +{ + Wire.beginTransmission(RTC8564_SLAVE_ADRS); + Wire.send(0x01); + Wire.endTransmission(); + Wire.requestFrom(RTC8564_SLAVE_ADRS, 1); + if(Wire.available()){ + return ((Wire.receive() & 0x04) != 0x04 ? false : true); + } + return false; +} + +uint8_t Rtc8564AttachInterrupt::seconds(uint8_t format) const { + if(format == Decimal) return BCD2Decimal(_seconds); + return _seconds; +} + +uint8_t Rtc8564AttachInterrupt::minutes(uint8_t format) const { + if(format == Decimal) return BCD2Decimal(_minutes); + return _minutes; +} + +uint8_t Rtc8564AttachInterrupt::hours(uint8_t format) const { + if(format == Decimal) return BCD2Decimal(_hours); + return _hours; +} + +uint8_t Rtc8564AttachInterrupt::days(uint8_t format) const { + if(format == Decimal) return BCD2Decimal(_days); + return _days; +} + +uint8_t Rtc8564AttachInterrupt::weekdays() const { + return _weekdays; +} + +uint8_t Rtc8564AttachInterrupt::months(uint8_t format) const { + if(format == Decimal) return BCD2Decimal(_months); + return _months; +} + +uint8_t Rtc8564AttachInterrupt::years(uint8_t format) const { + if(format == Decimal) return BCD2Decimal(_years); + return _years; +} + +bool Rtc8564AttachInterrupt::century() const { + return _century; +} + + +// Preinstantiate Objects ////////////////////////////////////////////////////// + +Rtc8564AttachInterrupt Rtc = Rtc8564AttachInterrupt(); diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/Rtc8564AttachInterrupt.h b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/Rtc8564AttachInterrupt.h new file mode 100644 index 0000000..3da7a01 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/Rtc8564AttachInterrupt.h @@ -0,0 +1,46 @@ +#ifndef Rtc8564AttachInterrupt_h +#define Rtc8564AttachInterrupt_h + +#include + +class Rtc8564AttachInterrupt +{ +private: + void init(void); + uint8_t _seconds; + uint8_t _minutes; + uint8_t _hours; + uint8_t _days; + uint8_t _weekdays; + uint8_t _months; + uint8_t _years; + bool _century; + +public: + enum { + BCD = 0, + Decimal = 1, + }; + Rtc8564AttachInterrupt(); + void begin(void); + void beginWithoutIsValid(void); + void initDatetime(uint8_t date_time[]); + bool isInitDatetime(void); + void sync(uint8_t date_time[],uint8_t size = 7); + void syncInterrupt(unsigned int mode, unsigned long term); + bool available(void); + bool isvalid(void); + bool isInterrupt(void); + uint8_t seconds(uint8_t format = Rtc8564AttachInterrupt::BCD) const; + uint8_t minutes(uint8_t format = Rtc8564AttachInterrupt::BCD) const; + uint8_t hours(uint8_t format = Rtc8564AttachInterrupt::BCD) const; + uint8_t days(uint8_t format = Rtc8564AttachInterrupt::BCD) const; + uint8_t weekdays() const; + uint8_t months(uint8_t format = Rtc8564AttachInterrupt::BCD) const; + uint8_t years(uint8_t format = Rtc8564AttachInterrupt::BCD) const; + bool century() const; +}; + +extern Rtc8564AttachInterrupt Rtc; + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/examples/.DS_Store b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/examples/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/examples/.DS_Store differ diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/examples/RTC8564DatetimeInit/RTC8564DatetimeInit.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/examples/RTC8564DatetimeInit/RTC8564DatetimeInit.pde new file mode 100644 index 0000000..8eeb8ac --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/examples/RTC8564DatetimeInit/RTC8564DatetimeInit.pde @@ -0,0 +1,86 @@ +/* + * sketch name : RTC8564DatetimeInit + * summary : RTC8564 init datetime and print datetime + */ + +#include +#include + +/* RTC timer start datetime */ +#define RTC_SEC 0x00 // seconds +#define RTC_MIN 0x52 // minute +#define RTC_HOUR 0x16 // hour +#define RTC_DAY 0x20 // day +#define RTC_WEEK 0x06 // week(00:Sun 〜 06:Sat) +#define RTC_MON 0x03 // month +#define RTC_YEAR 0x11 // year +byte date_time[7] = { + RTC_SEC + ,RTC_MIN + ,RTC_HOUR + ,RTC_DAY + ,RTC_WEEK + ,RTC_MON + ,RTC_YEAR +}; + +/* periodic timer interval unit 0:seconds/1:minute */ +#define RTC_INTERRUPT_MODE 0 + +/* measurement interval(RTC interrupt interval) */ +#define RTC_INTERRUPT_TERM 10 + +/* external interrupt pin */ +#define RTC_INTERRUPT_PIN 2 + +/* measurements enable flag */ +volatile int flg = LOW; + +void setup() { + + Serial.begin(9600); + + // RTC datetime set + Rtc.initDatetime(date_time); + + // RTC datetime init without RTC periodic timer interval check continuity + Rtc.beginWithoutIsValid(); + + // RTC interrupt init + Rtc.syncInterrupt(RTC_INTERRUPT_MODE, RTC_INTERRUPT_TERM); + + // interrupt init + pinMode(RTC_INTERRUPT_PIN, INPUT); + digitalWrite(RTC_INTERRUPT_PIN, HIGH); + attachInterrupt(0, printDatetime, FALLING); +} + +void loop() { + if (flg) { + ReadRTC(); + flg = LOW; + } +} + +void printDatetime(void) +{ + flg = HIGH; +} + +void ReadRTC() +{ + Rtc.available(); + Serial.print(Rtc.years(), HEX); + Serial.print("/"); + Serial.print(Rtc.months(), HEX); + Serial.print("/"); + Serial.print(Rtc.days(), HEX); + Serial.print(" "); + Serial.print(Rtc.hours(), HEX); + Serial.print(":"); + Serial.print(Rtc.minutes(), HEX); + Serial.print(":"); + Serial.print(Rtc.seconds(), HEX); + Serial.print(" "); + Serial.println((int)Rtc.weekdays()); +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/examples/Rtc8564AttachInterrupt/Rtc8564AttachInterrupt.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/examples/Rtc8564AttachInterrupt/Rtc8564AttachInterrupt.pde new file mode 100644 index 0000000..6ce9b8b --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/examples/Rtc8564AttachInterrupt/Rtc8564AttachInterrupt.pde @@ -0,0 +1,90 @@ +/* + * sketch name : RTC8564AttachInterrupt + * summary : RTC8564 print datetime + */ + +#include +#include + +/* RTC timer start datetime */ +#define RTC_SEC 0x00 // seconds +#define RTC_MIN 0x00 // minute +#define RTC_HOUR 0x22 // hour +#define RTC_DAY 0x01 // day +#define RTC_WEEK 0x02 // weed(00:Sun 〜 06:Sat) +#define RTC_MON 0x03 // month +#define RTC_YEAR 0x11 // year +byte date_time[7] = { + RTC_SEC + ,RTC_MIN + ,RTC_HOUR + ,RTC_DAY + ,RTC_WEEK + ,RTC_MON + ,RTC_YEAR +}; + +/* periodic timer interval unit 0:seconds/1:minute */ +#define RTC_INTERRUPT_MODE 0 + +/* measurement interval(RTC interrupt interval) */ +#define RTC_INTERRUPT_TERM 10 + +/* external interrupt pin */ +#define RTC_INTERRUPT_PIN 2 + +/* measurements enable flag */ +volatile int flg = LOW; + +void setup() { + + Serial.begin(9600); + + // RTC datetime set + Rtc.initDatetime(date_time); + + // RTC start + Rtc.begin(); + + // RTC periodic timer interval check continuity + if (!Rtc.isInterrupt()) { + + // RTC interrupt init + Rtc.syncInterrupt(RTC_INTERRUPT_MODE, RTC_INTERRUPT_TERM); + } + + // interrupt init + pinMode(RTC_INTERRUPT_PIN, INPUT); + digitalWrite(RTC_INTERRUPT_PIN, HIGH); + attachInterrupt(0, printDatetime, FALLING); +} + +void loop() { + if (flg) { + ReadRTC(); + flg = LOW; + } +} + +void printDatetime(void) +{ + flg = HIGH; +} + +void ReadRTC() +{ + Rtc.available(); + Serial.print(Rtc.years(), HEX); + Serial.print("/"); + Serial.print(Rtc.months(), HEX); + Serial.print("/"); + Serial.print(Rtc.days(), HEX); + Serial.print(" "); + Serial.print(Rtc.hours(), HEX); + Serial.print(":"); + Serial.print(Rtc.minutes(), HEX); + Serial.print(":"); + Serial.print(Rtc.seconds(), HEX); + Serial.print(" "); + Serial.println((int)Rtc.weekdays()); +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/keywords.txt b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/keywords.txt new file mode 100644 index 0000000..95d9e49 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch03 Jungle power/libraries/Rtc8564AttachInterrupt/keywords.txt @@ -0,0 +1,37 @@ +####################################### +# Syntax Coloring Map For RTC8564 +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### +Rtc8564AttachInterrupt KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +seconds KEYWORD2 +minutes KEYWORD2 +hours KEYWORD2 +days KEYWORD2 +weekdays KEYWORD2 +months KEYWORD2 +years KEYWORD2 +century KEYWORD2 +sync KEYWORD2 +available KEYWORD2 +initDatetime KEYWORD2 +isInitDatetime KEYWORD2 +syncInterrupt KEYWORD2 +isInterrupt KEYWORD2 +beginWithoutIsValid KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +Rtc KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/FreakDuinoChibi/CH4_1_simple_Chibi_coms/CH4_1_simple_Chibi_coms.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/FreakDuinoChibi/CH4_1_simple_Chibi_coms/CH4_1_simple_Chibi_coms.pde new file mode 100644 index 0000000..aafa54d --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/FreakDuinoChibi/CH4_1_simple_Chibi_coms/CH4_1_simple_Chibi_coms.pde @@ -0,0 +1,40 @@ +/* Chibi for Arduino, Example 2 +This is the same Hello World example except that both +transmit and receive handling is included. +*/ + +#include + +byte msg[] = "Hello World"; + +void setup() +{ + Serial.begin(57600); + chibiInit(); +} + +void loop() +{ + // We're going to add 1 to the message length to handle the + // terminating character '/0'. We're also sending a broadcast so + // any node in listening range will hear the message. + chibiTx(BROADCAST_ADDR, msg, 12); + + // if any data is received, then print it to the terminal + if (chibiDataRcvd() == true) + { + byte buf[CHB_MAX_PAYLOAD]; // store the received data in here + + chibiGetData(buf); + + // The data consists of ASCII characters in byte (unsigned char) format. The print + // function requires ASCII characters be in char format so we need to inform the function + // that its okay to convert the format from unsigned char to char. + Serial.print((char *)buf); + } + + // delay half a second between transmission + delay(500); +} + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/FreakDuinoChibi/CH4_2_Sleeping_Chibi_Sensor/CH4_2_Sleeping_Chibi_Sensor.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/FreakDuinoChibi/CH4_2_Sleeping_Chibi_Sensor/CH4_2_Sleeping_Chibi_Sensor.pde new file mode 100644 index 0000000..463c8ec --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/FreakDuinoChibi/CH4_2_Sleeping_Chibi_Sensor/CH4_2_Sleeping_Chibi_Sensor.pde @@ -0,0 +1,106 @@ +#include +#include +#include +#include + +// Project variables +int A0raw, A1raw; +const int bufSize = 5; +byte XmitBuf[bufSize]; + +/* RTC preset clock*/ +#define RTC_SEC 0x00 // seconds +#define RTC_MIN 0x18 // minutes +#define RTC_HOUR 0x23 // hours +#define RTC_DAY 0x15 // day +#define RTC_WEEK 0x02 // weekday(00:sunday 〜 06:saturday) +#define RTC_MON 0x03 // month +#define RTC_YEAR 0x11 // year +byte date_time[7] = { + RTC_SEC + ,RTC_MIN + ,RTC_HOUR + ,RTC_DAY + ,RTC_WEEK + ,RTC_MON + ,RTC_YEAR +}; + +/* clock reset flag */ +boolean init_flg = false; + +/* countdown timer period */ +#define RTC_INTERRUPT_TERM 10 + +/* Arduino wake interupt pin */ +#define RTC_INTERRUPT_PIN 2 + +/* countdowntimer mode 0:seconds/1:minutes */ +#define RTC_INTERRUPT_MODE 0 + +void setup() { + Serial.begin(9600); + chibiInit(); + + // set the clock + Rtc.initDatetime(date_time); + + // RTC start + Rtc.begin(); + + // check for interrupt + if (!Rtc.isInterrupt()) { + + // set the interrupt + Rtc.syncInterrupt(RTC_INTERRUPT_MODE, RTC_INTERRUPT_TERM); + } + + // prepare the interrupt pin + pinMode(RTC_INTERRUPT_PIN, INPUT); + digitalWrite(RTC_INTERRUPT_PIN, HIGH); +} + +void loop() { + + // check the flag and read the clock data + if (init_flg) ReadRTC(); + init_flg = true; + + // stuff to do before sleep + // read the pins + A0raw = analogRead(A0); + A1raw = analogRead(A1); + Serial.print(A0raw); + Serial.print(" "); + Serial.println(A1raw); + + memcpy(XmitBuf, &A0raw, 2); + + chibiSleepRadio(0); // wake up the radio + delay(100); + chibiTx(BROADCAST_ADDR, XmitBuf, bufSize); + chibiSleepRadio(1); // go back to sleep + + // Arduino Sleep time! Dont put anything else in the main loop after this! + delay(100); + SleepClass::powerDownAndWakeupExternalEvent(0); +} + +void ReadRTC() +{ + Rtc.available(); + Serial.print(0x2000 + Rtc.years(), HEX); + Serial.print("/"); + Serial.print(Rtc.months(), HEX); + Serial.print("/"); + Serial.print(Rtc.days(), HEX); + Serial.print(" "); + Serial.print(Rtc.hours(), HEX); + Serial.print(":"); + Serial.print(Rtc.minutes(), HEX); + Serial.print(":"); + Serial.print(Rtc.seconds(), HEX); + Serial.print(" "); + Serial.println((int)Rtc.weekdays()); +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/FreakDuinoChibi/CH4_3_Chibi_Receiver/CH4_3_Chibi_Receiver.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/FreakDuinoChibi/CH4_3_Chibi_Receiver/CH4_3_Chibi_Receiver.pde new file mode 100644 index 0000000..5b664f8 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/FreakDuinoChibi/CH4_3_Chibi_Receiver/CH4_3_Chibi_Receiver.pde @@ -0,0 +1,20 @@ +#include +byte buf[CHB_MAX_PAYLOAD]; + +void setup() +{ + Serial.begin(57600); + chibiInit(); +} + +void loop() +{ + if (chibiDataRcvd() == true) + { + unsigned int rcv_data; + chibiGetData(buf); + Serial.println((char *)buf); + } +} + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/FreakDuinoChibi/CH4_4_TeleSensation_formattedMsgTransmitter/CH4_4_TeleSensation_formattedMsgTransmitter.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/FreakDuinoChibi/CH4_4_TeleSensation_formattedMsgTransmitter/CH4_4_TeleSensation_formattedMsgTransmitter.pde new file mode 100644 index 0000000..e51ecf4 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/FreakDuinoChibi/CH4_4_TeleSensation_formattedMsgTransmitter/CH4_4_TeleSensation_formattedMsgTransmitter.pde @@ -0,0 +1,93 @@ +#include +#include +#include +#include + +/* Project variables */ +const int bufSize = 30; +byte XmitBuf[bufSize]; + +/* RTC preset clock*/ +#define RTC_SEC 0x00 // seconds +#define RTC_MIN 0x18 // minutes +#define RTC_HOUR 0x23 // hours +#define RTC_DAY 0x15 // day +#define RTC_WEEK 0x02 // weekday(00:sunday 〜 06:saturday) +#define RTC_MON 0x03 // month +#define RTC_YEAR 0x11 // year +byte date_time[7] = { + RTC_SEC + ,RTC_MIN + ,RTC_HOUR + ,RTC_DAY + ,RTC_WEEK + ,RTC_MON + ,RTC_YEAR +}; + +/* clock reset flag */ +boolean init_flg = false; + +/* countdown timer period */ +#define RTC_INTERRUPT_TERM 10 + +/* Arduino wake interupt pin */ +#define RTC_INTERRUPT_PIN 2 + +/* countdowntimer mode 0:seconds/1:minutes */ +#define RTC_INTERRUPT_MODE 0 + + +void setup() { + chibiInit(); + Rtc.initDatetime(date_time); // set the clock + Rtc.begin(); // RTC start + if (!Rtc.isInterrupt()) { // check for interrupt + // set the interrupt + Rtc.syncInterrupt(RTC_INTERRUPT_MODE, RTC_INTERRUPT_TERM); + } + // prepare the interrupt pin + pinMode(RTC_INTERRUPT_PIN, INPUT); + digitalWrite(RTC_INTERRUPT_PIN, HIGH); +} + +void loop() { + + PrepMsg(); + WakeRadio(); + Transmit(); + // Arduino Sleep time! Dont put anything else in the main loop after this! + GoToSleep(); +} + +void PrepMsg() +{ + Rtc.available(); + char temp[bufSize]; + sprintf(temp, "%x,%x,%x,%x,%x,%x,%d,%d", + Rtc.months(), Rtc.days(), (0x2000 + Rtc.years()), + Rtc.hours(), Rtc.minutes(), Rtc.seconds(), + analogRead(A0), analogRead(A1)); + memcpy(XmitBuf, temp, bufSize); +} + +void WakeRadio() +{ + // wake the radio, transmit, then put it back to sleep + chibiSleepRadio(0); // wake up the radio + delay(100); // adjust min wakeup time before xmit +} + +void Transmit() +{ + chibiTx(BROADCAST_ADDR, XmitBuf, bufSize); +} + +void GoToSleep() +{ + chibiSleepRadio(1); // Sleep the radio + delay(100); // adjust min radio shutdown time + SleepClass::powerDownAndWakeupExternalEvent(0); +} + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Processing/CH4_8_TeleSensation_comTest/CH4_8_TeleSensation_comTest.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Processing/CH4_8_TeleSensation_comTest/CH4_8_TeleSensation_comTest.pde new file mode 100644 index 0000000..7f372cb --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Processing/CH4_8_TeleSensation_comTest/CH4_8_TeleSensation_comTest.pde @@ -0,0 +1,63 @@ +import processing.serial.*; +Serial SinkNode; +String Month, Day, Year, Hour, Minute, Second, NodeData0, NodeData1; + +void setup (){ + //sets up a serial connection named SinkNode. + //The value after Serial.list in the [] indicates the port + SinkNode = new Serial(this, Serial.list()[1], 57600); +} + +void draw() { + int gotData = 0; + while (gotData == 0){ + if (SinkNode.available() > 0) { + String data = SinkNode.readStringUntil('\n'); + if (data != null){ + gotData = parseString(data); + PrintData(); + } + } + } +} + + +int parseString (String serialString) { + String items[] = split(serialString, ','); + println("From SourceNode: " + serialString); + Month = items[0]; + Day = items[1]; + Year = items[2]; + Hour = items[3]; + Minute = items[4]; + Second = items[5]; + NodeData0 = items[6]; + NodeData1 = items[7]; + + if (items.length == 7) { + return 1; + } else { + return 0; + } +} + +void PrintData() { + print(Month); + print("/"); + print(Day); + print("/"); + print(Year); + print(" "); + print(Hour); + print(":"); + print(Minute); + print(":"); + print(Second); + print(" "); + print("A0 = "); + print(NodeData0); + print(" "); + print("A1 = "); + println(NodeData1); +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Processing/CH4_9_TeleSensation_dataLogger/CH4_9_TeleSensation_dataLogger.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Processing/CH4_9_TeleSensation_dataLogger/CH4_9_TeleSensation_dataLogger.pde new file mode 100644 index 0000000..d002e04 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Processing/CH4_9_TeleSensation_dataLogger/CH4_9_TeleSensation_dataLogger.pde @@ -0,0 +1,114 @@ +import processing.serial.*; +Serial SinkNode; +String Month, Day, Year, Hour, Minute, Second, NodeData0, NodeData1; + +// log file variables +String dataFolder = "../data/"; +String logfilename; // log file name +PrintWriter logFile; + +// State variable +boolean logging = false; + +void setup (){ + SinkNode = new Serial(this, Serial.list()[1], 57600); + + // set tentative file name + logfilename = dataFolder + "Save_the_World-" + nf(year(),4) + nf(month(),2) + nf(day(),2) + + "-" + nf(hour(),2) + nf(minute(),2) + nf(second(),2) + ".log"; + + startLogging(); +} + +void draw() { + int gotData = 0; + while (gotData == 0){ + if (SinkNode.available() > 0) { + String data = SinkNode.readStringUntil('\n'); + if (data != null){ + gotData = parseString(data); + writeLog(); + } + } + } +} + + +int parseString (String serialString) { + String items[] = split(serialString, ','); + println("From SourceNode: " + serialString); + Month = items[0]; + Day = items[1]; + Year = items[2]; + Hour = items[3]; + Minute = items[4]; + Second = items[5]; + NodeData0 = items[6]; + NodeData1 = items[7]; + + if (items.length == 7) { + return 1; + } else { + return 0; + } +} + + +String formatLogEntry() +{ + String log_entry = + Month + "/" + Day + "/" + Year + "," + + Hour + ":" + Minute + ":" + Second + "," + + NodeData0 + "," + NodeData1; + return log_entry; +} + +void writeLog() +{ + if (logging) + { + String log_entry = formatLogEntry(); + logFile.println(log_entry); + println(log_entry); + logFile.flush(); + } +} + +void startLogging() +{ + // open file + openLogFile(); + // start running + logging = true; + println("Started logging to " + logfilename); +} + +void stopLogging() +{ + logging = false; + closeLogFile(); + println("Stopped Logging."); +} + +void openLogFile() +{ + // logfilename = logfileTextField.getText(); + if (logfilename.equals("")) + { + // set tentative file name + logfilename = dataFolder + "Save_the_World-" + nf(year(),4) + nf(month(),2) + nf(day(),2) + + "-" + nf(hour(),2) + nf(minute(),2) + nf(second(),2) + ".log"; + } + logFile = createWriter(logfilename); +} + +void closeLogFile() +{ + logFile.flush(); + logFile.close(); + println("Log file close."); + // set tentative file name + logfilename = dataFolder + "Save_the_World-" + nf(year(),4) + nf(month(),2) + nf(day(),2) + + "-" + nf(hour(),2) + nf(minute(),2) + nf(second(),2) + ".log"; +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/CH4_7_Stalker_Sleep_test/CH4_7_Stalker_Sleep_test.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/CH4_7_Stalker_Sleep_test/CH4_7_Stalker_Sleep_test.pde new file mode 100644 index 0000000..594a4f2 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/CH4_7_Stalker_Sleep_test/CH4_7_Stalker_Sleep_test.pde @@ -0,0 +1,286 @@ +#include +#include "myRX8025.h" +#include + +//************************************** +// RX8025 stuff +unsigned char second = 0; +unsigned char minute = 0; +unsigned char hour = 0; +unsigned char weekday = 0; +unsigned char day = 0; +unsigned char month = 0; +unsigned char year = 0; +unsigned char Doffset = 0; +unsigned char alarmD_hour = 0; +unsigned char alarmD_minute = 0; +unsigned char alarmW_weekday = 0; +unsigned char alarmW_hour = 0; +unsigned char alarmW_minute = 0; +unsigned char RX8025_control_1 = 0; +unsigned char RX8025_control_2 = 0; +unsigned char RX8025_Reserved; + +unsigned char RX8025_time[7]= +{ +//second, minute, hour, week, date, month, year, BCD format + 0x00,0x45,0x14,0x03,0x28,0x05,0x11 +}; + +unsigned char RX8025_alarmD[2]= // daily alarm +{ + 0x15,0x12 // minute, hour +}; + +unsigned char RX8025_alarmW[3]= +{ + 0x45,0x07,0x06 // minute, hour, weekday +}; + +unsigned char RX8025_Control[2]= +{ + 0x25,0x00 // E - Set 24 hour clock, 1-minute interrupts + // F - clear all flags +}; // end RX8025 stuff + +//====================================== +// Sleep stuff +int wakePin = 2; // pin used for waking up +int sleepStatus = 0; // variable to store a request for sleep +int count = 0; // counter +// end sleep stuff + +//====================================== +// program stuff +int LEDpin = 8; + +//====================================== +//====================================== +void wakeUpNow() // here the interrupt is handled after wakeup +{ + // execute code here after wake-up before returning to the loop() function + digitalWrite(LEDpin, HIGH); +} + +//====================================== +void setup(void) +{ + Wire.begin(); + Serial.begin(9600); + RX8025_init(); +// setRtcAlarmD(); // this is where you would set these +// setRtcAlarmW(); // if you were going to use specific time alarms + + pinMode(LEDpin, OUTPUT);//LED pin set to OUTPUT + pinMode(wakePin, INPUT); // setup interrupt pin + attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function + // wakeUpNow when pin 2 gets LOW + digitalWrite(LEDpin, HIGH); +} + +//====================================== +void loop(void) +{ + delay(500); + RtcClearFlags(); + getRtcTime(); + print_RX8025_time(); + print_AlarmD(); + print_AlarmW(); + getRtcAll(); + print_RX8025_all(); + Serial.println("--------------next--data---------------"); + Serial_Command(); + Serial.println(); + sleepNow(); +} + +//====================================== +void print_RX8025_all(void) +{ + Serial.print(second,DEC); + Serial.print(" "); + Serial.print(minute,DEC); + Serial.print(" "); + Serial.print(hour,DEC); + Serial.print(" "); + Serial.print(weekday,DEC); + Serial.print(" "); + Serial.print(day,DEC); + Serial.print(" "); + Serial.print(month,DEC); + Serial.print(" "); + Serial.print(year,DEC); + Serial.print(" "); + Serial.print(Doffset,DEC); + Serial.print(" "); + Serial.print(alarmW_minute,DEC); + Serial.print(" "); + Serial.print(alarmW_hour,DEC); + Serial.print(" "); + Serial.print(alarmW_weekday,DEC); + Serial.print(" "); + Serial.print(alarmD_minute,DEC); + Serial.print(" "); + Serial.print(alarmD_hour,DEC); + Serial.print(" "); + Serial.print(RX8025_Reserved,DEC); + Serial.print(" "); + Serial.print(RX8025_control_1,DEC); + Serial.print(" "); + Serial.println(RX8025_control_2,DEC); +} + +//====================================== +void print_RX8025_time(void) +{ + Serial.print(year,DEC); + Serial.print("/"); + Serial.print(month,DEC); + Serial.print("/"); + Serial.print(day,DEC); + switch(weekday) + { + case 0x00: + { + Serial.print("/Sunday "); + break; + } + case 0x01: + { + Serial.print("/Monday "); + break; + } + case 0x02: + { + Serial.print("/Tuesday "); + break; + } + case 0x03: + { + Serial.print("/Wednesday "); + break; + } + case 0x04: + { + Serial.print("/Thursday "); + break; + } + case 0x05: + { + Serial.print("/Friday "); + break; + } + case 0x06: + { + Serial.print("/Saturday "); + break; + } + } + Serial.print(hour,DEC); + Serial.print(":"); + Serial.print(minute,DEC); + Serial.print(":"); + Serial.println(second,DEC); + } + +//====================================== +void print_AlarmD(void) +{ + Serial.print("Daily Alarm = "); + Serial.print(alarmD_hour,DEC); + Serial.print(":"); + Serial.println(alarmD_minute,DEC); +} + +//====================================== +void print_AlarmW(void) +{ + Serial.print("Weekly Alarm = "); + Serial.print(alarmW_hour,DEC); + Serial.print(":"); + Serial.print(alarmW_minute,DEC); + Serial.print(" "); + Serial.println(alarmW_weekday,DEC); +} + +//====================================== +void Serial_Command(void) +{ + if(Serial.available()==3) + { + if(Serial.read()=='c') + { + if(Serial.read()=='c') + { + if(Serial.read()=='c') + { + Serial.println("Got Serial data"); + } + } + } + } + else + { + Serial.flush(); + } +} + +//====================================== +void sleepNow() // here we put the arduino to sleep + +{ + digitalWrite(LEDpin, LOW); + /* Now is the time to set the sleep mode. In the Atmega8 datasheet + * http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf on page 35 + * there is a list of sleep modes which explains which clocks and + * wake up sources are available in which sleep mode. + * + * In the avr/sleep.h file, the call names of these sleep modes are to be found: + * + * The 5 different modes are: + * SLEEP_MODE_IDLE -the least power savings + * SLEEP_MODE_ADC + * SLEEP_MODE_PWR_SAVE + * SLEEP_MODE_STANDBY + * SLEEP_MODE_PWR_DOWN -the most power savings + * + * For now, we want as much power savings as possible, so we + * choose the according + * sleep mode: SLEEP_MODE_PWR_DOWN + * + */ + set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here + sleep_enable(); // enables the sleep bit in the mcucr register + // so sleep is possible. just a safety pin + /* Now it is time to enable an interrupt. We do it here so an + * accidentally pushed interrupt button doesn't interrupt + * our running program. if you want to be able to run + * interrupt code besides the sleep function, place it in + * setup() for example. + * + * In the function call attachInterrupt(A, B, C) + * A can be either 0 or 1 for interrupts on pin 2 or 3. + * + * B Name of a function you want to execute at interrupt for A. + * + * C Trigger mode of the interrupt pin. can be: + * LOW a low level triggers + * CHANGE a change in level triggers + * RISING a rising edge of a level triggers + * FALLING a falling edge of a level triggers + * + * In all but the IDLE sleep modes only LOW can be used. + */ + attachInterrupt(0,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function + // wakeUpNow when pin 2 gets LOW + delay(500); // keeps serial output clean after waking up. + sleep_mode(); // here the device is actually put to sleep!! + // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP + sleep_disable(); // first thing after waking from sleep: + // disable sleep... + detachInterrupt(0); // disables interrupt 0 on pin 2 so the + // wakeUpNow code will not be executed + // during normal running time. +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/CH4_8_Xbee_sleep_sensor/CH4_8_Xbee_sleep_sensor.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/CH4_8_Xbee_sleep_sensor/CH4_8_Xbee_sleep_sensor.pde new file mode 100644 index 0000000..17cc292 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/CH4_8_Xbee_sleep_sensor/CH4_8_Xbee_sleep_sensor.pde @@ -0,0 +1,221 @@ +#include +#include "myRX8025.h" +#include "tmp102.h" +#include "TF.h" +#include "Battery.h" +#include +#include +#include + +//************************************** +// RX8025 stuff +unsigned char second = 0; +unsigned char minute = 0; +unsigned char hour = 0; +unsigned char weekday = 0; +unsigned char day = 0; +unsigned char month = 0; +unsigned char year = 0; +unsigned char Doffset = 0; +unsigned char alarmD_hour = 0; +unsigned char alarmD_minute = 0; +unsigned char alarmW_weekday = 0; +unsigned char alarmW_hour = 0; +unsigned char alarmW_minute = 0; +unsigned char RX8025_control_1 = 0; +unsigned char RX8025_control_2 = 0; +unsigned char RX8025_Reserved; + +unsigned char RX8025_time[7]= +{ +//second, minute, hour, week, date, month, year, BCD format + 0x00,0x45,0x14,0x03,0x28,0x05,0x11 +}; + +unsigned char RX8025_alarmD[2]= // daily alarm +{ + 0x15,0x12 // minute, hour +}; + +unsigned char RX8025_alarmW[3]= +{ + 0x45,0x07,0x06 // minute, hour, weekday +}; + +unsigned char RX8025_Control[2]= +{ + 0x25,0x00 // E - Set 24 hour clock, 1-minute interrupts + // F - clear all flags +}; // end RX8025 stuff + +//====================================== +// Sleep stuff +int wakePin = 2; // pin used for waking up +int beeSleep = 4; // set high to sleep, low to wake up +int beeSleepStatus = 5; // gets the Bee sleep status + +//====================================== +// program stuff +int LEDpin = 8; +float convertedtemp; /* We then need to multiply our two bytes by + a scaling factor, mentioned in the datasheet. */ +int tmp102_val; /* an int is capable of storing two bytes, this is + where we "chuck" the two bytes together. */ +char name[] = "data.log"; // file name in TF card root dir +unsigned int bat_read; //analog read battery voltage +float bat_voltage; //battery voltage +unsigned char charge_status; //battery charge status + + +//====================================== +//====================================== +void wakeUpNow() // here the interrupt is handled after wakeup +{ + // execute code here after wake-up before returning to the loop() function + digitalWrite(LEDpin, HIGH); + digitalWrite(beeSleep, LOW); // wake the bee +} + +//====================================== +void setup(void) +{ + Wire.begin(); + Serial.begin(9600); + RX8025_init(); + // TF_card_init(); + tmp102_init(); + Battery_init(); + pinMode(LEDpin, OUTPUT);//LED pin set to OUTPUT + pinMode(wakePin, INPUT); // setup interrupt pin + pinMode(beeSleep, OUTPUT); + pinMode(beeSleepStatus, INPUT); + attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function + // wakeUpNow when pin 2 gets LOW + digitalWrite(LEDpin, HIGH); + digitalWrite(beeSleep, LOW); // wake the bee +} + +//====================================== +void loop(void) +{ + while(digitalRead(beeSleepStatus) == LOW) { + break; + } + + RtcClearFlags(); + getRtcTime(); + getTemp102(); + Battery_charge_status(); + Battery_voltage_read(); + // write_data_to_TF(); + + //debug data + print_data(); + Serial_Command(); // pending return commands? + + sleepNow(); // nighty night +} + + +//====================================== +void print_data(void) +{ + Serial.print(month,DEC); + Serial.print(","); + Serial.print(day,DEC); + Serial.print(","); + Serial.print(2000 + year,DEC); + Serial.print(","); + Serial.print(hour,DEC); + Serial.print(","); + Serial.print(minute,DEC); + Serial.print(","); + Serial.print(second,DEC); + Serial.print(","); + Serial.print(bat_voltage); + Serial.print(","); + Serial.print(convertedtemp); + Serial.println("\0"); + } + +//====================================== +void Serial_Command(void) +{ + if(Serial.available()==3) + { + if(Serial.read()=='c') + { + if(Serial.read()=='c') + { + if(Serial.read()=='c') + { + Serial.println("Got Serial data"); + } + } + } + } + else + { + Serial.flush(); + } +} + +//====================================== +void sleepNow() // here we put the arduino to sleep + +{ + digitalWrite(LEDpin, LOW); + digitalWrite(beeSleep, HIGH); + /* Now is the time to set the sleep mode. In the Atmega8 datasheet + * http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf on page 35 + * there is a list of sleep modes which explains which clocks and + * wake up sources are available in which sleep mode. + * + * In the avr/sleep.h file, the call names of these sleep modes are to be found: + * + * The 5 different modes are: + * SLEEP_MODE_IDLE -the least power savings + * SLEEP_MODE_ADC + * SLEEP_MODE_PWR_SAVE + * SLEEP_MODE_STANDBY + * SLEEP_MODE_PWR_DOWN -the most power savings + * + * For now, we want as much power savings as possible, so we + * choose the according + * sleep mode: SLEEP_MODE_PWR_DOWN + * + */ + set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here + sleep_enable(); // enables the sleep bit in the mcucr register + // so sleep is possible. just a safety pin + /* Now it is time to enable an interrupt. We do it here so an + * accidentally pushed interrupt button doesn't interrupt + * our running program. if you want to be able to run + * interrupt code besides the sleep function, place it in + * setup() for example. + * + * In the function call attachInterrupt(A, B, C) + * A can be either 0 or 1 for interrupts on pin 2 or 3. + * + * B Name of a function you want to execute at interrupt for A. + * + * C Trigger mode of the interrupt pin. can be: + * LOW a low level triggers + * CHANGE a change in level triggers + * RISING a rising edge of a level triggers + * FALLING a falling edge of a level triggers + * + * In all but the IDLE sleep modes only LOW can be used. + */ + attachInterrupt(0,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function + // wakeUpNow when pin 2 gets LOW + delay(500); // keeps serial output clean after waking up. + sleep_mode(); // here the device is actually put to sleep!! + // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP + sleep_disable(); // first thing after waking from sleep: + // disable sleep... + detachInterrupt(0); // disables interrupt 0 on pin 2 so the + // wakeUpNow code will not be executed + // during normal running time. +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/Battery.cpp b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/Battery.cpp new file mode 100644 index 0000000..e1a86bb --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/Battery.cpp @@ -0,0 +1,84 @@ +#include "Battery.h" +#include + +//********************************** +/* +void Battery_init(void) + init Battery IOs and ADC7 + */ +void Battery_init(void) +{ + analogReference(INTERNAL);//internal 1.1v in Atmega328 + pinMode(CH_Status,INPUT); + pinMode(OK_Status,INPUT); + digitalWrite(CH_Status,HIGH);//pull high + digitalWrite(OK_Status,HIGH);//pull high + Battery_charge_status(); + Battery_voltage_read(); +} + +//==================================== +void Battery_charge_status(void) +{ + boolean OK = digitalRead(OK_Status); + boolean CH = digitalRead(CH_Status); + if(OK&&CH)//Charger is sleeping, will auto start charge battery when FB voltage less than 3.0v + { + charge_status = 0x01; + } + + else if(CH)//Charge complete + { + charge_status = 0x02; + } + + else if(OK)//Charging + { + charge_status = 0x04; + } + + else//USB power exsit, battery is not exist + { + charge_status = 0x08; + //Serial.println("Bad Battery or Battery is not exist"); + } +} + +//===================================== +void Battery_voltage_read(void) +{ + bat_read = analogRead(BAT_voltage); + + // (1/1024)*6=0.0064453125, + bat_voltage = (float)bat_read * 0.0064453125; + + //Serial.print(" -->Battery data = "); + //Serial.println(bat_read); + + if(bat_read<570)// less than 3.48v + { + Serial.println("low battery, please recharge"); + } + else if(bat_read>680)// more than 4.22 v + { + Serial.println("out of range, over charge?"); + } + else + { + // battery is fine + } +} + + + + + + + + + + + + + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/Battery.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/Battery.h new file mode 100644 index 0000000..c121f99 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/Battery.h @@ -0,0 +1,19 @@ +#ifndef Battery_h +#define Battery_h + +//********************************************** +#define CH_Status 6 +#define OK_Status 7 +#define BAT_voltage 7 +//============================================== +extern unsigned int bat_read; +extern float bat_voltage; +extern unsigned char charge_status; + +//============================================== +void Battery_init(void); +void Battery_voltage_read(void); +void Battery_charge_status(void); +//********************************************** + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/RX8025.cpp b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/RX8025.cpp new file mode 100644 index 0000000..b93380f --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/RX8025.cpp @@ -0,0 +1,80 @@ +#include +#include "RX8025.h" +//******************************************************************** + +//=============================================== +#define RX8025_address 0x32 + +unsigned char RX8025_Control[2]= +{ + 0x20,0x00 +}; + +//=============================================== +void setRtcTime(void) +{ + Wire.beginTransmission(RX8025_address); + Wire.send(0x00); + for(unsigned char i=0; i<7; i++) + { + Wire.send(RX8025_time[i]); + } + Wire.endTransmission(); +} + +//=============================================== +uint8_t bcd2bin (uint8_t val) +{ + return val - 6 * (val >> 4); +} + +uint8_t bin2bcd (uint8_t val) +{ + return val + 6 * (val / 10); +} + +//=============================================== +void getRtcTime(void) +{ + unsigned char i=0; + Wire.beginTransmission(RX8025_address); + Wire.send(0x00); + Wire.endTransmission();// + Wire.requestFrom(RX8025_address,8); + RX8025_time[i]= Wire.receive();//not use + while(Wire.available()) + { + RX8025_time[i]= Wire.receive(); + i++; + } + Wire.endTransmission();// + + year = bcd2bin(RX8025_time[6]&0xff); + month = bcd2bin(RX8025_time[5]&0x1f); + date = bcd2bin(RX8025_time[4]&0x3f); + week = bcd2bin(RX8025_time[3]&0x07); + hour = bcd2bin(RX8025_time[2]&0x3f); + minute = bcd2bin(RX8025_time[1]&0x7f); + second = bcd2bin(RX8025_time[0]&0x7f); +} + +//=============================================== +void RX8025_init(void) +{ + Wire.begin(); + Wire.beginTransmission(RX8025_address);//clear power on reset flag, set to 24hr format + Wire.send(0xe0); + for(unsigned char i=0; i<2; i++) + { + Wire.send(RX8025_Control[i]); + } + Wire.endTransmission(); + //setRtcTime(); +} + + + + + + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/RX8025.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/RX8025.h new file mode 100644 index 0000000..ad4523c --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/RX8025.h @@ -0,0 +1,35 @@ +#ifndef RX8025_h +#define RX8025_h + +#define RX8025_SEC 0 +#define RX8025_MIN 1 +#define RX8025_HR 2 +#define RX8025_WEEK 3 +#define RX8025_DATE 4 +#define RX8025_MTH 5 +#define RX8025_YR 6 +#define RX8025_Doffset 7 +#define RX8025_AW_MIN 8 +#define RX8025_AW_HR 9 +#define RX8025_AW_WEEK 10 +#define RX8025_AD_MIN 11 +#define RX8025_AD_HR 12 +#define RX8025_CTL1 14 +#define RX8025_CTL2 15 + +extern unsigned char RX8025_time[7]; + +extern unsigned char hour; +extern unsigned char minute; +extern unsigned char second; +extern unsigned char week; +extern unsigned char year; +extern unsigned char month; +extern unsigned char date; + + +void RX8025_init(void); +void getRtcTime(void); +void setRtcTime(void); + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/Stlker_logger_AM06_Serial.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/Stlker_logger_AM06_Serial.pde new file mode 100644 index 0000000..ed60701 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/Stlker_logger_AM06_Serial.pde @@ -0,0 +1,185 @@ +#include + +#include "tmp102.h" +#include "TF.h" +#include "Battery.h" +#include "RX8025.h" + +#include +#include +#include // use functions to print strings from flash memory + +//************************************** + +float convertedtemp; /* We then need to multiply our two bytes by a scaling factor, mentioned in the datasheet. */ +int tmp102_val; /* an int is capable of storing two bytes, this is where we "chuck" the two bytes together. */ + +char name[] = "data.log";/* file name in TF card root dir */ + +unsigned int bat_read;//analog read battery voltage +float bat_voltage;//battery voltage +unsigned char charge_status;//battery charge status + +unsigned char hour=0; +unsigned char minute=0; +unsigned char second=0; +unsigned char week=0; +unsigned char year=0; +unsigned char month=0; +unsigned char date=0; + +unsigned char RX8025_time[7]= +{ + 0x00,0x54,0x09,0x03,0x10,0x11,0x10 //second, minute, hour, week, date, month, year, BCD format +}; + + +//====================================== +void setup(void) +{ + Serial.begin(38400); + RX8025_init(); + TF_card_init(); + tmp102_init(); + Battery_init(); + pinMode(8,OUTPUT);//LED pin set to OUTPUT + pinMode(5,OUTPUT);//Bee power control pin +} +//====================================== +void loop(void) +{ + digitalWrite(8,HIGH);//LED pin set to OUTPUT + getTemp102(); + Battery_charge_status(); + Battery_voltage_read(); + getRtcTime(); + write_data_to_TF(); + digitalWrite(8,LOW); + + //debug data + print_RX8025_time(); + print_tmp102_data(); + print_Battery_data(); + Serial.println("--------------next--data---------------"); + Serial_Command(); + Serial.println(); + + delay(2000); +} + +//================================= +void print_tmp102_data(void) +{ + Serial.print("tep102_temperature = "); + Serial.println(convertedtemp); +} + +//================================== +void print_Battery_data(void) +{ + switch (charge_status) + { + case 0x01: + { + Serial.print("CH_sleeping"); + break; + } + case 0x02: + { + Serial.print("CH_complete"); + break; + } + case 0x04: + { + Serial.print("CH_charging"); + break; + } + case 0x08: + { + Serial.print("CH_bat_not_exist"); + break; + } + } + Serial.print(" battery voltage = "); + Serial.println(bat_voltage); +} +//============================================== +void print_RX8025_time(void) +{ + Serial.print(year,DEC); + Serial.print("/"); + Serial.print(month,DEC); + Serial.print("/"); + Serial.print(date,DEC); + switch(week) + { + case 0x00: + { + Serial.print("/Sunday "); + break; + } + case 0x01: + { + Serial.print("/Monday "); + break; + } + case 0x02: + { + Serial.print("/Tuesday "); + break; + } + case 0x03: + { + Serial.print("/Wednesday "); + break; + } + case 0x04: + { + Serial.print("/Thursday "); + break; + } + case 0x05: + { + Serial.print("/Friday "); + break; + } + case 0x06: + { + Serial.print("/Saturday "); + break; + } + } + Serial.print(hour,DEC); + Serial.print(":"); + Serial.print(minute,DEC); + Serial.print(":"); + Serial.println(second,DEC); +} + +//====================================== +void Serial_Command(void) +{ + if(Serial.available()==3) + { + if(Serial.read()=='c') + { + if(Serial.read()=='c') + { + if(Serial.read()=='c') + { + Serial.println("Got Serial data"); + } + } + } + } + else + { + Serial.flush(); + } +} + + + + + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/TF.cpp b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/TF.cpp new file mode 100644 index 0000000..558ab76 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/TF.cpp @@ -0,0 +1,182 @@ +#include "TF.h" + +//********************************** + + +SdCard card; +Fat16 file; + +// store error strings in flash to save RAM +#define error(s) error_P(PSTR(s)) + +void error_P(const char* str) +{ + PgmPrint("error: "); + SerialPrintln_P(str); + if (card.errorCode) + { + PgmPrint("SD error: "); + Serial.println(card.errorCode, HEX); + } + Serial.println("TF error"); +} + +void TF_card_init(void) +{ + //Serial.println(); + pinMode(SD_power_IO,INPUT);//extern power + //pinMode(SD_power_IO,OUTPUT); + //digitalWrite(SD_power_IO,HIGH);//power up SD card + //delay(10); + //PgmPrintln("Type any character to start"); + + // initialize the SD card + if (!card.init()) error("card.init"); + + // initialize a FAT16 volume + if (!Fat16::init(&card)) error("Fat16::init"); + // clear write error + file.writeError = false; +} + +//======================================= +void store_tmp102_data(void) +{ + file.print("tep102_temperature = "); + file.println(convertedtemp); +} + +//======================================== +void store_Battery_data(void) +{ + switch (charge_status) + { + case 0x01: + { + file.print("CH_sleeping"); + break; + } + case 0x02: + { + file.print("CH_complete"); + break; + } + case 0x04: + { + file.print("CH_charging"); + break; + } + case 0x08: + { + file.print("CH_bat_not_exist"); + break; + } + } + file.print(" battery voltage = "); + file.println(bat_voltage); +} + +//============================= +void store_RTC_time(void) +{ + /* unsigned char RX8025_time[7]= + { + 0x15,0x44,0x14,0x03,0x03,0x11,0x10 //second, minute, hour, week, date, month, year, BCD format + }; + */ + + file.print(year,DEC); + file.print("/"); + file.print(month,DEC); + file.print("/"); + file.print(date,DEC); + switch(week) + { + case 0x00: + { + file.print("/Sunday "); + break; + } + case 0x01: + { + file.print("/Monday "); + break; + } + case 0x02: + { + file.print("/Tuesday "); + break; + } + case 0x03: + { + file.print("/Wednesday "); + break; + } + case 0x04: + { + file.print("/Thursday "); + break; + } + case 0x05: + { + file.print("/Friday "); + break; + } + case 0x06: + { + file.print("/Saturday "); + break; + } + } + file.print(hour,DEC); + file.print(":"); + file.print(minute,DEC); + file.print(":"); + file.println(second,DEC); +} + +//====================================== +void write_data_to_TF(void) +{ + // O_CREAT - create the file if it does not exist + // O_APPEND - seek to the end of the file prior to each write + // O_WRITE - open for write + if (!file.open(name, O_CREAT | O_APPEND | O_WRITE)) + { + error("open"); + } + + + store_RTC_time(); + store_tmp102_data(); + store_Battery_data(); + + file.println("--------------next--data---------------"); + file.println(); + + if (file.writeError) + { + error("write"); + } + if (!file.close()) + { + error("close"); + } +} + + + + + + + + + + + + + + + + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/TF.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/TF.h new file mode 100644 index 0000000..ae194c0 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/TF.h @@ -0,0 +1,40 @@ +#ifndef TF_h +#define TF_h + +//********************************************** +/* + * Append Example + * + * This sketch shows how to use open for append and the Arduino Print class + * with Fat16. + */ +#include +#include // use functions to print strings from flash memory + + +#define SD_power_IO 4 + +//============================================== +extern char name[];//file name in TF card root dir + +extern float convertedtemp; +extern int tmp102_val; + +extern float bat_voltage; +extern unsigned int bat_read; +extern unsigned char charge_status; + +extern unsigned char hour; +extern unsigned char minute; +extern unsigned char second; +extern unsigned char week; +extern unsigned char year; +extern unsigned char month; +extern unsigned char date; +extern unsigned char RX8025_time[7]; +//============================================== +void TF_card_init(void); +void write_data_to_TF(void); +//********************************************** + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/tmp102.cpp b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/tmp102.cpp new file mode 100644 index 0000000..d2aae39 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/tmp102.cpp @@ -0,0 +1,71 @@ +#include "tmp102.h" + +//********************************** +void tmp102_init(void) +{ + Wire.begin(); // start the I2C library +} + + +void getTemp102(void) +{ + unsigned char firstbyte; + unsigned char secondbyte; //these are the bytes we read from the TMP102 temperature registers + unsigned int complement;// = 0xe70 - 1 + + //float correctedtemp; + // The sensor overreads (?) + + /* Reset the register pointer (by default it is ready to read temperatures) + You can alter it to a writeable register and alter some of the configuration - + the sensor is capable of alerting you if the temperature is above or below a specified threshold. */ + + Wire.beginTransmission(TMP102_I2C_ADDRESS); //Say hi to the sensor. + Wire.send(0x00); + Wire.endTransmission(); + Wire.requestFrom(TMP102_I2C_ADDRESS, 2); + Wire.endTransmission(); + + firstbyte = (Wire.receive()); + /*read the TMP102 datasheet - here we read one byte from + each of the temperature registers on the TMP102*/ + secondbyte = (Wire.receive()); + /*The first byte contains the most significant bits, and + the second the less significant */ + tmp102_val = ((firstbyte) << 4); + /* MSB */ + tmp102_val |= (secondbyte >> 4); + /* LSB is ORed into the second 4 bits of our byte. + Bitwise maths is a bit funky, but there's a good tutorial on the playground*/ + + /* + + Serial.println(); + Serial.print("complement1 = 0x"); + Serial.println(complement,HEX); + + complement ^= 0xfff; + + Serial.println(); + Serial.print("complement2 = 0x"); + Serial.println(complement,HEX); + */ + + if(tmp102_val&0x800)//negative temperature + { + complement = tmp102_val - 1; + complement ^= 0xfff; + convertedtemp = complement * 0.0625 * (-1); + } + else + { + convertedtemp = tmp102_val * 0.0625; + } + //correctedtemp = convertedtemp - 5; + /* See the above note on overreading */ +} + + + + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/tmp102.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/tmp102.h new file mode 100644 index 0000000..0bd56c9 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/Xbee_and_Stalker_ver20/Stlker_logger_AM06_Serial/tmp102.h @@ -0,0 +1,33 @@ +#ifndef tmp102_h +#define tmp102_h + +//********************************************** +#include +#include +#define TMP102_I2C_ADDRESS 72 /* This is the I2C address for our chip. +This value is correct if you tie the ADD0 pin to ground. See the datasheet for some other values. */ + +/* + Table 1. Pointer Register Byte + P7 P6 P5 P4 P3 P2 P1 P0 + 0 0 0 0 0 0 Register Bits + + P1 P0 REGISTER + 0 0 Temperature Register (Read Only) + 0 1 Configuration Register (Read/Write) + 1 0 T LOW Register (Read/Write) + 1 1 T HIGH Register (Read/Write) + */ + +//============================================== +extern float convertedtemp; +extern int tmp102_val; +//============================================== +void tmp102_init(void); +void getTemp102(void); +//********************************************** + +#endif + + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/Fat16.cpp b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/Fat16.cpp new file mode 100644 index 0000000..190356a --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/Fat16.cpp @@ -0,0 +1,974 @@ +/* Arduino FAT16 Library + * Copyright (C) 2008 by William Greiman + * + * This file is part of the Arduino FAT16 Library + * + * This Library 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 Library 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 the Arduino Fat16 Library. If not, see + * . + */ +#include +#include "WProgram.h" +#include "Fat16.h" +//----------------------------------------------------------------------------- +// volume info +uint8_t Fat16::volumeInitialized_ = 0; // true if FAT16 volume is valid +uint8_t Fat16::fatCount_; // number of file allocation tables +uint8_t Fat16::blocksPerCluster_; // must be power of 2 +uint16_t Fat16::rootDirEntryCount_; // should be 512 for FAT16 +fat_t Fat16::blocksPerFat_; // number of blocks in one FAT +fat_t Fat16::clusterCount_; // total clusters in volume +uint32_t Fat16::fatStartBlock_; // start of first FAT +uint32_t Fat16::rootDirStartBlock_; // start of root dir +uint32_t Fat16::dataStartBlock_; // start of data clusters +//------------------------------------------------------------------------------ +// raw block cache +SdCard *Fat16::rawDev_ = 0; // class for block read and write +uint32_t Fat16::cacheBlockNumber_ = 0XFFFFFFFF; // init to invalid block number +cache16_t Fat16::cacheBuffer_; // 512 byte cache for SdCard +uint8_t Fat16::cacheDirty_ = 0; // cacheFlush() will write block if true +uint32_t Fat16::cacheMirrorBlock_ = 0; // mirror block for second FAT +//------------------------------------------------------------------------------ +// callback function for date/time +void (*Fat16::dateTime_)(uint16_t* date, uint16_t* time) = NULL; + +#if ALLOW_DEPRECATED_FUNCTIONS +void (*Fat16::oldDateTime_)(uint16_t& date, uint16_t& time) = NULL; // NOLINT +#endif // ALLOW_DEPRECATED_FUNCTIONS +//------------------------------------------------------------------------------ +// format 8.3 name for directory entry +static uint8_t make83Name(const char* str, uint8_t* name) { + uint8_t c; + uint8_t n = 7; // max index for part before dot + uint8_t i = 0; + // blank fill name and extension + while (i < 11)name[i++] = ' '; + i = 0; + while ((c = *str++) != '\0') { + if (c == '.') { + if (n == 10) return false; // only one dot allowed + n = 10; // max index for full 8.3 name + i = 8; // place for extension + } else { + // illegal FAT characters + PGM_P p = PSTR("|<>^+=?/[];,*\"\\"); + uint8_t b; + while ((b = pgm_read_byte(p++))) if (b == c) return false; + // check length and only allow ASCII printable characters + if (i > n || c < 0X21 || c > 0X7E)return false; + // only upper case allowed in 8.3 names - convert lower to upper + name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a'); + } + } + // must have a file name, extension is optional + return name[0] != ' '; +} +//============================================================================== +// Fat16 member functions +//------------------------------------------------------------------------------ +uint8_t Fat16::addCluster(void) { + // start search after last cluster of file or at cluster two in FAT + fat_t freeCluster = curCluster_ ? curCluster_ : 1; + for (fat_t i = 0; ; i++) { + // return no free clusters + if (i >= clusterCount_) return false; + // Fat has clusterCount + 2 entries + if (freeCluster > clusterCount_) freeCluster = 1; + freeCluster++; + fat_t value; + if (!fatGet(freeCluster, &value)) return false; + if (value == 0) break; + } + // mark cluster allocated + if (!fatPut(freeCluster, FAT16EOC)) return false; + + if (curCluster_ != 0) { + // link cluster to chain + if (!fatPut(curCluster_, freeCluster)) return false; + } else { + // first cluster of file so update directory entry + flags_ |= F_FILE_DIR_DIRTY; + firstCluster_ = freeCluster; + } + curCluster_ = freeCluster; + return true; +} +//------------------------------------------------------------------------------ +// +dir_t* Fat16::cacheDirEntry(uint16_t index, uint8_t action) { + if (index >= rootDirEntryCount_) return NULL; + if (!cacheRawBlock(rootDirStartBlock_ + (index >> 4), action)) return NULL; + return &cacheBuffer_.dir[index & 0XF]; +} +//------------------------------------------------------------------------------ +// +uint8_t Fat16::cacheFlush(void) { + if (cacheDirty_) { + if (!rawDev_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) { + return false; + } + // mirror FAT tables + if (cacheMirrorBlock_) { + if (!rawDev_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) { + return false; + } + cacheMirrorBlock_ = 0; + } + cacheDirty_ = 0; + } + return true; +} +//------------------------------------------------------------------------------ +// +uint8_t Fat16::cacheRawBlock(uint32_t blockNumber, uint8_t action) { + if (cacheBlockNumber_ != blockNumber) { + if (!cacheFlush()) return false; + if (!rawDev_->readBlock(blockNumber, cacheBuffer_.data)) return false; + cacheBlockNumber_ = blockNumber; + } + cacheDirty_ |= action; + return true; +} +//------------------------------------------------------------------------------ +/** + * Close a file and force cached data and directory information + * to be written to the storage device. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include no file is open or an I/O error. + */ +uint8_t Fat16::close(void) { + if (!sync())return false; + flags_ = 0; + return true; +} +//------------------------------------------------------------------------------ +/** + * Return a files directory entry + * + * \param[out] dir Location for return of the files directory entry. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t Fat16::dirEntry(dir_t* dir) { + if (!sync()) return false; + dir_t* p = cacheDirEntry(dirEntryIndex_, CACHE_FOR_WRITE); + if (!p) return false; + memcpy(dir, p, sizeof(dir_t)); + return true; +} +//------------------------------------------------------------------------------ +uint8_t Fat16::fatGet(fat_t cluster, fat_t* value) { + if (cluster > (clusterCount_ + 1)) return false; + uint32_t lba = fatStartBlock_ + (cluster >> 8); + if (lba != cacheBlockNumber_) { + if (!cacheRawBlock(lba)) return false; + } + *value = cacheBuffer_.fat[cluster & 0XFF]; + return true; +} +//------------------------------------------------------------------------------ +uint8_t Fat16::fatPut(fat_t cluster, fat_t value) { + if (cluster < 2) return false; + if (cluster > (clusterCount_ + 1)) return false; + uint32_t lba = fatStartBlock_ + (cluster >> 8); + if (lba != cacheBlockNumber_) { + if (!cacheRawBlock(lba)) return false; + } + cacheBuffer_.fat[cluster & 0XFF] = value; + cacheSetDirty(); + // mirror second FAT + if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; + return true; +} +//------------------------------------------------------------------------------ +// free a cluster chain +uint8_t Fat16::freeChain(fat_t cluster) { + while (1) { + fat_t next; + if (!fatGet(cluster, &next)) return false; + if (!fatPut(cluster, 0)) return false; + if (isEOC(next)) return true; + cluster = next; + } +} +//------------------------------------------------------------------------------ +/** + * Initialize a FAT16 volume. + * + * \param[in] dev The SdCard where the volume is located. + * + * \param[in] part The partition to be used. Legal values for \a part are + * 1-4 to use the corresponding partition on a device formatted with + * a MBR, Master Boot Record, or zero if the device is formatted as + * a super floppy with the FAT boot sector in block zero. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. reasons for + * failure include not finding a valid FAT16 file system in the + * specified partition, a call to init() after a volume has + * been successful initialized or an I/O error. + * + */ +uint8_t Fat16::init(SdCard* dev, uint8_t part) { + // error if invalid partition + if (part > 4) return false; + rawDev_ = dev; + uint32_t volumeStartBlock = 0; + // if part == 0 assume super floppy with FAT16 boot sector in block zero + // if part > 0 assume mbr volume with partition table + if (part) { + if (!cacheRawBlock(volumeStartBlock)) return false; + volumeStartBlock = cacheBuffer_.mbr.part[part - 1].firstSector; + } + if (!cacheRawBlock(volumeStartBlock)) return false; + // check boot block signature + if (cacheBuffer_.data[510] != BOOTSIG0 || + cacheBuffer_.data[511] != BOOTSIG1) return false; + bpb_t* bpb = &cacheBuffer_.fbs.bpb; + fatCount_ = bpb->fatCount; + blocksPerCluster_ = bpb->sectorsPerCluster; + blocksPerFat_ = bpb->sectorsPerFat16; + rootDirEntryCount_ = bpb->rootDirEntryCount; + fatStartBlock_ = volumeStartBlock + bpb->reservedSectorCount; + rootDirStartBlock_ = fatStartBlock_ + bpb->fatCount*bpb->sectorsPerFat16; + dataStartBlock_ = rootDirStartBlock_ + + ((32*bpb->rootDirEntryCount + 511)/512); + uint32_t totalBlocks = bpb->totalSectors16 ? + bpb->totalSectors16 : bpb->totalSectors32; + clusterCount_ = (totalBlocks - (dataStartBlock_ - volumeStartBlock)) + /bpb->sectorsPerCluster; + // verify valid FAT16 volume + if (bpb->bytesPerSector != 512 // only allow 512 byte blocks + || bpb->sectorsPerFat16 == 0 // zero for FAT32 + || clusterCount_ < 4085 // FAT12 if true + || totalBlocks > 0X800000 // Max size for FAT16 volume + || bpb->reservedSectorCount == 0 // invalid volume + || bpb->fatCount == 0 // invalid volume + || bpb->sectorsPerFat16 < (clusterCount_ >> 8) // invalid volume + || bpb->sectorsPerCluster == 0 // invalid volume + // power of 2 test + || bpb->sectorsPerCluster & (bpb->sectorsPerCluster - 1)) { + // not a usable FAT16 bpb + return false; + } + volumeInitialized_ = 1; + return true; +} +//------------------------------------------------------------------------------ +/** List directory contents to Serial. + * + * \param[in] flags The inclusive OR of + * + * LS_DATE - %Print file modification date + * + * LS_SIZE - %Print file size. + */ +void Fat16::ls(uint8_t flags) { + dir_t d; + for (uint16_t index = 0; readDir(&d, &index, DIR_ATT_VOLUME_ID); index++) { + // print file name with possible blank fill + printDirName(d, flags & (LS_DATE | LS_SIZE) ? 14 : 0); + + // print modify date/time if requested + if (flags & LS_DATE) { + printFatDate(d.lastWriteDate); + Serial.print(' '); + printFatTime(d.lastWriteTime); + } + + // print size if requested + if (DIR_IS_FILE(&d) && (flags & LS_SIZE)) { + Serial.print(' '); + Serial.print(d.fileSize); + } + Serial.println(); + } +} +//------------------------------------------------------------------------------ +/** + * Open a file by file name. + * + * \note The file must be in the root directory and must have a DOS + * 8.3 name. + * + * \param[in] fileName A valid 8.3 DOS name for a file in the root directory. + * + * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive + * OR of flags from the following list + * + * O_READ - Open for reading. + * + * O_RDONLY - Same as O_READ. + * + * O_WRITE - Open for writing. + * + * O_WRONLY - Same as O_WRITE. + * + * O_RDWR - Open for reading and writing. + * + * O_APPEND - If set, the file offset shall be set to the end of the + * file prior to each write. + * + * O_CREAT - If the file exists, this flag has no effect except as noted + * under O_EXCL below. Otherwise, the file shall be created + * + * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists. + * + * O_SYNC - Call sync() after each write. This flag should not be used with + * write(uint8_t), write_P(PGM_P), writeln_P(PGM_P), or the Arduino Print class. + * These functions do character a time writes so sync() will be called + * after each byte. + * + * O_TRUNC - If the file exists and is a regular file, and the file is + * successfully opened and is not read only, its length shall be truncated to 0. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include the FAT volume has not been initialized, + * a file is already open, \a fileName is invalid, the file does not exist, + * is a directory, or can't be opened in the access mode specified by oflag. + */ +uint8_t Fat16::open(const char* fileName, uint8_t oflag) { + uint8_t dname[11]; // name formated for dir entry + int16_t empty = -1; // index of empty slot + dir_t* p; // pointer to cached dir entry + + if (!volumeInitialized_ || isOpen()) return false; + + // error if invalid name + if (!make83Name(fileName, dname)) return false; + + for (uint16_t index = 0; index < rootDirEntryCount_; index++) { + if (!(p = cacheDirEntry(index))) return false; + if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) { + // remember first empty slot + if (empty < 0) empty = index; + // done if no entries follow + if (p->name[0] == DIR_NAME_FREE) break; + } else if (!memcmp(dname, p->name, 11)) { + // don't open existing file if O_CREAT and O_EXCL + if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false; + + // open existing file + return open(index, oflag); + } + } + // error if directory is full + if (empty < 0) return false; + + // only create file if O_CREAT and O_WRITE + if ((oflag & (O_CREAT | O_WRITE)) != (O_CREAT | O_WRITE)) return false; + + if (!(p = cacheDirEntry(empty, CACHE_FOR_WRITE))) return false; + + // initialize as empty file + memset(p, 0, sizeof(dir_t)); + memcpy(p->name, dname, 11); + + // set timestamps + if (dateTime_) { + // call user function + dateTime_(&p->creationDate, &p->creationTime); + } else { + // use default date/time + p->creationDate = FAT_DEFAULT_DATE; + p->creationTime = FAT_DEFAULT_TIME; + } + p->lastAccessDate = p->creationDate; + p->lastWriteDate = p->creationDate; + p->lastWriteTime = p->creationTime; + + // insure created directory entry will be written to storage device + if (!cacheFlush()) return false; + + // open entry + return open(empty, oflag); +} +//------------------------------------------------------------------------------ +/** + * Open a file by file index. + * + * \param[in] index The root directory index of the file to be opened. See \link + * Fat16::readDir() readDir()\endlink. + * + * \param[in] oflag See \link Fat16::open(const char*, uint8_t)\endlink. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include the FAT volume has not been initialized, + * a file is already open, \a index is invalid or is not the index of a + * file or the file cannot be opened in the access mode specified by oflag. + */ +uint8_t Fat16::open(uint16_t index, uint8_t oflag) { + if (!volumeInitialized_ || isOpen()) return false; + if ((oflag & O_TRUNC) && !(oflag & O_WRITE)) return false; + dir_t* d = cacheDirEntry(index); + // if bad file index or I/O error + if (!d) return false; + + // error if unused entry + if (d->name[0] == DIR_NAME_FREE || d->name[0] == DIR_NAME_DELETED) { + return false; + } + // error if long name, volume label or subdirectory + if ((d->attributes & (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY)) != 0) { + return false; + } + // don't allow write or truncate if read-only + if (d->attributes & DIR_ATT_READ_ONLY) { + if (oflag & (O_WRITE | O_TRUNC)) return false; + } + + curCluster_ = 0; + curPosition_ = 0; + dirEntryIndex_ = index; + fileSize_ = d->fileSize; + firstCluster_ = d->firstClusterLow; + flags_ = oflag & (O_ACCMODE | O_SYNC | O_APPEND); + + if (oflag & O_TRUNC ) return truncate(0); + return true; +} +//------------------------------------------------------------------------------ +/** %Print the name field of a directory entry in 8.3 format to Serial. + * + * \param[in] dir The directory structure containing the name. + * \param[in] width Blank fill name if length is less than \a width. + */ +void Fat16::printDirName(const dir_t& dir, uint8_t width) { + uint8_t w = 0; + for (uint8_t i = 0; i < 11; i++) { + if (dir.name[i] == ' ')continue; + if (i == 8) { + Serial.print('.'); + w++; + } + Serial.print(dir.name[i]); + w++; + } + if (DIR_IS_SUBDIR(&dir)) { + Serial.print('/'); + w++; + } + while (w < width) { + Serial.print(' '); + w++; + } +} +//------------------------------------------------------------------------------ +/** %Print a directory date field to Serial. + * + * Format is yyyy-mm-dd. + * + * \param[in] fatDate The date field from a directory entry. + */ +void Fat16::printFatDate(uint16_t fatDate) { + Serial.print(FAT_YEAR(fatDate)); + Serial.print('-'); + printTwoDigits(FAT_MONTH(fatDate)); + Serial.print('-'); + printTwoDigits(FAT_DAY(fatDate)); +} +//------------------------------------------------------------------------------ +/** %Print a directory time field to Serial. + * + * Format is hh:mm:ss. + * + * \param[in] fatTime The time field from a directory entry. + */ +void Fat16::printFatTime(uint16_t fatTime) { + printTwoDigits(FAT_HOUR(fatTime)); + Serial.print(':'); + printTwoDigits(FAT_MINUTE(fatTime)); + Serial.print(':'); + printTwoDigits(FAT_SECOND(fatTime)); +} + +//------------------------------------------------------------------------------ +/** %Print a value as two digits to Serial. + * + * \param[in] v Value to be printed, 0 <= \a v <= 99 + */ +void Fat16::printTwoDigits(uint8_t v) { + char str[3]; + str[0] = '0' + v/10; + str[1] = '0' + v % 10; + str[2] = 0; + Serial.print(str); +} +//------------------------------------------------------------------------------ +/** + * Read the next byte from a file. + * + * \return For success read returns the next byte in the file as an int. + * If an error occurs or end of file is reached -1 is returned. + */ +int16_t Fat16::read(void) { + uint8_t b; + return read(&b, 1) == 1 ? b : -1; +} +//------------------------------------------------------------------------------ +/** + * Read data from a file at starting at the current file position. + * + * \param[out] buf Pointer to the location that will receive the data. + * + * \param[in] nbyte Maximum number of bytes to read. + * + * \return For success read returns the number of bytes read. + * A value less than \a nbyte, including zero, may be returned + * if end of file is reached. + * If an error occurs, read returns -1. Possible errors include + * read called before a file has been opened, the file has not been opened in + * read mode, a corrupt file system, or an I/O error. + */ +int16_t Fat16::read(void* buf, uint16_t nbyte) { + // convert void pointer to uin8_t pointer + uint8_t* dst = reinterpret_cast(buf); + + // error if not open for read + if (!(flags_ & O_READ)) return -1; + + // don't read beyond end of file + if ((curPosition_ + nbyte) > fileSize_) nbyte = fileSize_ - curPosition_; + + // bytes left to read in loop + uint16_t nToRead = nbyte; + while (nToRead > 0) { + uint8_t blkOfCluster = blockOfCluster(curPosition_); + uint16_t blockOffset = cacheDataOffset(curPosition_); + if (blkOfCluster == 0 && blockOffset == 0) { + // start next cluster + if (curCluster_ == 0) { + curCluster_ = firstCluster_; + } else { + if (!fatGet(curCluster_, &curCluster_)) return -1; + } + // return error if bad cluster chain + if (curCluster_ < 2 || isEOC(curCluster_)) return -1; + } + // cache data block + if (!cacheRawBlock(dataBlockLba(curCluster_, blkOfCluster))) return -1; + + // location of data in cache + uint8_t* src = cacheBuffer_.data + blockOffset; + + // max number of byte available in block + uint16_t n = 512 - blockOffset; + + // lesser of available and amount to read + if (n > nToRead) n = nToRead; + + // copy data to caller + memcpy(dst, src, n); + + curPosition_ += n; + dst += n; + nToRead -= n; + } + return nbyte; +} +//------------------------------------------------------------------------------ +/** + * Read the next short, 8.3, directory entry. + * + * Unused entries and entries for long names are skipped. + * + * \param[out] dir Location that will receive the entry. + * + * \param[in,out] index The search starts at \a index and \a index is + * updated with the root directory index of the found directory entry. + * If the entry is a file, it may be opened by calling + * \link Fat16::open(uint16_t, uint8_t) \endlink. + * + * \param[in] skip Skip entries that have these attributes. If \a skip + * is not specified, the default is to skip the volume label and directories. + * + * \return The value one, true, is returned for success and the value zero, + * false, is returned if an error occurs or the end of the root directory is + * reached. On success, \a entry is set to the index of the found directory + * entry. + */ +uint8_t Fat16::readDir(dir_t* dir, uint16_t* index, uint8_t skip) { + dir_t* p; + for (uint16_t i = *index; ; i++) { + if (i >= rootDirEntryCount_) return false; + if (!(p = cacheDirEntry(i))) return false; + + // done if beyond last used entry + if (p->name[0] == DIR_NAME_FREE) return false; + + // skip deleted entry + if (p->name[0] == DIR_NAME_DELETED) continue; + + // skip long names + if ((p->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME) continue; + + // skip if attribute match + if (p->attributes & skip) continue; + + // return found index + *index = i; + break; + } + memcpy(dir, p, sizeof(dir_t)); + return true; +} +//------------------------------------------------------------------------------ +/** + * Remove a file. The directory entry and all data for the file are deleted. + * + * \note This function should not be used to delete the 8.3 version of a + * file that has a long name. For example if a file has the long name + * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include the file is not open for write + * or an I/O error occurred. + */ +uint8_t Fat16::remove(void) { + // error if file is not open for write + if (!(flags_ & O_WRITE)) return false; + if (firstCluster_) { + if (!freeChain(firstCluster_)) return false; + } + dir_t* d = cacheDirEntry(dirEntryIndex_, CACHE_FOR_WRITE); + if (!d) return false; + d->name[0] = DIR_NAME_DELETED; + flags_ = 0; + return cacheFlush(); +} +//------------------------------------------------------------------------------ +/** + * Remove a file. + * + * The directory entry and all data for the file are deleted. + * + * \param[in] fileName The name of the file to be removed. + * + * \note This function should not be used to delete the 8.3 version of a + * file that has a long name. For example if a file has the long name + * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include the file is read only, \a fileName is not found + * or an I/O error occurred. + */ +uint8_t Fat16::remove(const char* fileName) { + Fat16 file; + if (!file.open(fileName, O_WRITE)) return false; + return file.remove(); +} +//------------------------------------------------------------------------------ +/** + * Sets the file's read/write position. + * + * \param[in] pos The new position in bytes from the beginning of the file. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t Fat16::seekSet(uint32_t pos) { + // error if file not open or seek past end of file + if (!isOpen() || pos > fileSize_) return false; + if (pos == 0) { + // set position to start of file + curCluster_ = 0; + curPosition_ = 0; + return true; + } + fat_t n = ((pos - 1) >> 9)/blocksPerCluster_; + if (pos < curPosition_ || curPosition_ == 0) { + // must follow chain from first cluster + curCluster_ = firstCluster_; + } else { + // advance from curPosition + n -= ((curPosition_ - 1) >> 9)/blocksPerCluster_; + } + while (n--) { + if (!fatGet(curCluster_, &curCluster_)) return false; + } + curPosition_ = pos; + return true; +} +//------------------------------------------------------------------------------ +/** + * The sync() call causes all modified data and directory fields + * to be written to the storage device. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include a call to sync() before a file has been + * opened or an I/O error. + */ +uint8_t Fat16::sync(void) { + if (flags_ & F_FILE_DIR_DIRTY) { + // cache directory entry + dir_t* d = cacheDirEntry(dirEntryIndex_, CACHE_FOR_WRITE); + if (!d) return false; + + // update file size and first cluster + d->fileSize = fileSize_; + d->firstClusterLow = firstCluster_; + + // set modify time if user supplied a callback date/time function + if (dateTime_) { + dateTime_(&d->lastWriteDate, &d->lastWriteTime); + d->lastAccessDate = d->lastWriteDate; + } + flags_ &= ~F_FILE_DIR_DIRTY; + } + return cacheFlush(); +} +//------------------------------------------------------------------------------ +/** + * The timestamp() call sets a file's timestamps in its directory entry. + * + * \param[in] flags Values for \a flags are constructed by a bitwise-inclusive + * OR of flags from the following list + * + * T_ACCESS - Set the file's last access date. + * + * T_CREATE - Set the file's creation date and time. + * + * T_WRITE - Set the file's last write/modification date and time. + * + * \param[in] year Valid range 1980 - 2107 inclusive. + * + * \param[in] month Valid range 1 - 12 inclusive. + * + * \param[in] day Valid range 1 - 31 inclusive. + * + * \param[in] hour Valid range 0 - 23 inclusive. + * + * \param[in] minute Valid range 0 - 59 inclusive. + * + * \param[in] second Valid range 0 - 59 inclusive + * + * \note It is possible to set an invalid date since there is no check for + * the number of days in a month. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t Fat16::timestamp(uint8_t flags, uint16_t year, uint8_t month, + uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { + if (!isOpen() + || year < 1980 + || year > 2107 + || month < 1 + || month > 12 + || day < 1 + || day > 31 + || hour > 23 + || minute > 59 + || second > 59) { + return false; + } + dir_t* d = cacheDirEntry(dirEntryIndex_, CACHE_FOR_WRITE); + if (!d) return false; + uint16_t dirDate = FAT_DATE(year, month, day); + uint16_t dirTime = FAT_TIME(hour, minute, second); + if (flags & T_ACCESS) { + d->lastAccessDate = dirDate; + } + if (flags & T_CREATE) { + d->creationDate = dirDate; + d->creationTime = dirTime; + // seems to be units of 1/100 second not 1/10 as Microsoft standard states + d->creationTimeTenths = second & 1 ? 100 : 0; + } + if (flags & T_WRITE) { + d->lastWriteDate = dirDate; + d->lastWriteTime = dirTime; + } + cacheSetDirty(); + return sync(); +} +//------------------------------------------------------------------------------ +/** + * Truncate a file to a specified length. The current file position + * will be maintained if it is less than or equal to \a length otherwise + * it will be set to end of file. + * + * \param[in] length The desired length for the file. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include file is read only, file is a directory, + * \a length is greater than the current file size or an I/O error occurs. + */ +uint8_t Fat16::truncate(uint32_t length) { + // error if file is not open for write + if (!(flags_ & O_WRITE)) return false; + + if (length > fileSize_) return false; + + // fileSize and length are zero - nothing to do + if (fileSize_ == 0) return true; + uint32_t newPos = curPosition_ > length ? length : curPosition_; + if (length == 0) { + // free all clusters + if (!freeChain(firstCluster_)) return false; + curCluster_ = firstCluster_ = 0; + } else { + fat_t toFree; + if (!seekSet(length)) return false; + if (!fatGet(curCluster_, &toFree)) return false; + if (!isEOC(toFree)) { + // free extra clusters + if (!fatPut(curCluster_, FAT16EOC)) return false; + if (!freeChain(toFree)) return false; + } + } + fileSize_ = length; + flags_ |= F_FILE_DIR_DIRTY; + if (!sync()) return false; + return seekSet(newPos); +} +//------------------------------------------------------------------------------ +/** + * Write data at the current position of an open file. + * + * \note Data is moved to the cache but may not be written to the + * storage device until sync() is called. + * + * \param[in] buf Pointer to the location of the data to be written. + * + * \param[in] nbyte Number of bytes to write. + * + * \return For success write() returns the number of bytes written, always + * \a nbyte. If an error occurs, write() returns -1. Possible errors include + * write() is called before a file has been opened, the file has not been opened + * for write, device is full, a corrupt file system or an I/O error. + * + */ +int16_t Fat16::write(const void* buf, uint16_t nbyte) { + uint16_t nToWrite = nbyte; + const uint8_t* src = reinterpret_cast(buf); + + // error if file is not open for write + if (!(flags_ & O_WRITE)) goto writeErrorReturn; + + // go to end of file if O_APPEND + if ((flags_ & O_APPEND) && curPosition_ != fileSize_) { + if (!seekEnd()) goto writeErrorReturn; + } + while (nToWrite > 0) { + uint8_t blkOfCluster = blockOfCluster(curPosition_); + uint16_t blockOffset = cacheDataOffset(curPosition_); + if (blkOfCluster == 0 && blockOffset == 0) { + // start of new cluster + if (curCluster_ == 0) { + if (firstCluster_ == 0) { + // allocate first cluster of file + if (!addCluster()) goto writeErrorReturn; + } else { + curCluster_ = firstCluster_; + } + } else { + fat_t next; + if (!fatGet(curCluster_, &next)) goto writeErrorReturn; + if (isEOC(next)) { + // add cluster if at end of chain + if (!addCluster()) goto writeErrorReturn; + } else { + curCluster_ = next; + } + } + } + uint32_t lba = dataBlockLba(curCluster_, blkOfCluster); + if (blockOffset == 0 && curPosition_ >= fileSize_) { + // start of new block don't need to read into cache + if (!cacheFlush()) goto writeErrorReturn; + cacheBlockNumber_ = lba; + cacheSetDirty(); + } else { + // rewrite part of block + if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) return -1; + } + uint8_t* dst = cacheBuffer_.data + blockOffset; + + // max space in block + uint16_t n = 512 - blockOffset; + + // lesser of space and amount to write + if (n > nToWrite) n = nToWrite; + + // copy data to cache + memcpy(dst, src, n); + + curPosition_ += n; + nToWrite -= n; + src += n; + } + if (curPosition_ > fileSize_) { + // update fileSize and insure sync will update dir entry + fileSize_ = curPosition_; + flags_ |= F_FILE_DIR_DIRTY; + } else if (dateTime_ && nbyte) { + // insure sync will update modified date and time + flags_ |= F_FILE_DIR_DIRTY; + } + + if (flags_ & O_SYNC) { + if (!sync()) goto writeErrorReturn; + } + return nbyte; + + writeErrorReturn: + writeError = true; + return -1; +} +//------------------------------------------------------------------------------ +/** + * Write a byte to a file. Required by the Arduino Print class. + * + * Use Fat16::writeError to check for errors. + */ +void Fat16::write(uint8_t b) { + write(&b, 1); +} +//------------------------------------------------------------------------------ +/** + * Write a string to a file. Used by the Arduino Print class. + * + * Use Fat16::writeError to check for errors. + */ +void Fat16::write(const char* str) { + write(str, strlen(str)); +} +//------------------------------------------------------------------------------ +/** + * Write a PROGMEM string to a file. + * + * Use Fat16::writeError to check for errors. + */ +void Fat16::write_P(PGM_P str) { + for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c); +} +//------------------------------------------------------------------------------ +/** + * Write a PROGMEM string followed by CR/LF to a file. + * + * Use Fat16::writeError to check for errors. + */ +void Fat16::writeln_P(PGM_P str) { + write_P(str); + println(); +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/Fat16.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/Fat16.h new file mode 100644 index 0000000..e966415 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/Fat16.h @@ -0,0 +1,370 @@ +/* Arduino FAT16 Library + * Copyright (C) 2008 by William Greiman + * + * This file is part of the Arduino FAT16 Library + * + * This Library 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 Library 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 the Arduino Fat16 Library. If not, see + * . + */ +#ifndef Fat16_h +#define Fat16_h +/** + * \file + * Fat16 class + */ +#include +#include +#include +#include "SdCard.h" +#include "FatStructs.h" +#include "Fat16Config.h" + +// flags for ls() +/** ls() flag to print modify date */ +uint8_t const LS_DATE = 1; +/** ls() flag to print file size */ +uint8_t const LS_SIZE = 2; + +// use the gnu style oflags +/** open for reading */ +uint8_t const O_READ = 0X01; +/** same as O_READ */ +uint8_t const O_RDONLY = O_READ; +/** open for write */ +uint8_t const O_WRITE = 0X02; +/** same as O_WRITE */ +uint8_t const O_WRONLY = O_WRITE; +/** open for reading and writing */ +uint8_t const O_RDWR = O_READ | O_WRITE; +/** mask for access modes */ +uint8_t const O_ACCMODE = O_READ | O_WRITE; +/** The file offset shall be set to the end of the file prior to each write. */ +uint8_t const O_APPEND = 0X04; +/** synchronous writes - call sync() after each write */ +uint8_t const O_SYNC = 0X08; +/** create the file if nonexistent */ +uint8_t const O_CREAT = 0X10; +/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */ +uint8_t const O_EXCL = 0X20; +/** truncate the file to zero length */ +uint8_t const O_TRUNC = 0X40; + +// flags for timestamp +/** set the file's last access date */ +uint8_t const T_ACCESS = 1; +/** set the file's creation date and time */ +uint8_t const T_CREATE = 2; +/** Set the file's write date and time */ +uint8_t const T_WRITE = 4; + +/** date field for FAT directory entry */ +static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) { + return (year - 1980) << 9 | month << 5 | day; +} +/** year part of FAT directory date field */ +static inline uint16_t FAT_YEAR(uint16_t fatDate) { + return 1980 + (fatDate >> 9); +} +/** month part of FAT directory date field */ +static inline uint8_t FAT_MONTH(uint16_t fatDate) { + return (fatDate >> 5) & 0XF; +} +/** day part of FAT directory date field */ +static inline uint8_t FAT_DAY(uint16_t fatDate) { + return fatDate & 0X1F; +} +/** time field for FAT directory entry */ +static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) { + return hour << 11 | minute << 5 | second >> 1; +} +/** hour part of FAT directory time field */ +static inline uint8_t FAT_HOUR(uint16_t fatTime) { + return fatTime >> 11; +} +/** minute part of FAT directory time field */ +static inline uint8_t FAT_MINUTE(uint16_t fatTime) { + return(fatTime >> 5) & 0X3F; +} +/** second part of FAT directory time field */ +static inline uint8_t FAT_SECOND(uint16_t fatTime) { + return 2*(fatTime & 0X1F); +} +/** Default date for file timestamps is 1 Jan 2000 */ +uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1; +/** Default time for file timestamp is 1 am */ +uint16_t const FAT_DEFAULT_TIME = (1 << 11); +//------------------------------------------------------------------------------ +/** + * \typedef fat_t + * + * \brief Type for FAT16 entry + */ +typedef uint16_t fat_t; +/** + * \union cache16_t + * + * \brief Cache buffer data type + * + */ +union cache16_t { + /** Used to access cached file data blocks. */ + uint8_t data[512]; + /** Used to access cached FAT entries. */ + fat_t fat[256]; + /** Used to access cached directory entries. */ + dir_t dir[16]; + /** Used to access a cached Master Boot Record. */ + mbr_t mbr; + /** Used to access to a cached FAT16 boot sector. */ + fbs_t fbs; +}; +//------------------------------------------------------------------------------ +/** \class Fat16 + * \brief Fat16 implements a minimal Arduino FAT16 Library + * + * Fat16 does not support subdirectories or long file names. + */ +class Fat16 : public Print { + public: + /* + * Public functions + */ + /** create with file closed */ + Fat16(void) : flags_(0) {} + /** \return The current cluster number. */ + fat_t curCluster(void) const {return curCluster_;} + uint8_t close(void); + /** \return The count of clusters in the FAT16 volume. */ + static fat_t clusterCount(void) {return clusterCount_;} + /** \return The number of 512 byte blocks in a cluster */ + static uint8_t clusterSize(void) {return blocksPerCluster_;} + /** \return The current file position. */ + uint32_t curPosition(void) const {return curPosition_;} + /** + * Set the date/time callback function + * + * \param[in] dateTime The user's callback function. The callback + * function is of the form: + * + * \code + * void dateTime(uint16_t* date, uint16_t* time) { + * uint16_t year; + * uint8_t month, day, hour, minute, second; + * + * // User gets date and time from GPS or real-time clock here + * + * // return date using FAT_DATE macro to format fields + * *date = FAT_DATE(year, month, day); + * + * // return time using FAT_TIME macro to format fields + * *time = FAT_TIME(hour, minute, second); + * } + * \endcode + * + * Sets the function that is called when a file is created or when + * a file's directory entry is modified by sync(). All timestamps, + * access, creation, and modify, are set when a file is created. + * sync() maintains the last access date and last modify date/time. + * + * See the timestamp() function. + */ + static void dateTimeCallback( + void (*dateTime)(uint16_t* date, uint16_t* time)) { + dateTime_ = dateTime; + } + /** + * Cancel the date/time callback function. + */ + static void dateTimeCallbackCancel(void) {dateTime_ = NULL;} + uint8_t dirEntry(dir_t* dir); + + /** \return The file's size in bytes. */ + uint32_t fileSize(void) const {return fileSize_;} + static uint8_t init(SdCard* dev, uint8_t part); + /** + * Initialize a FAT16 volume. + * + * First try partition 1 then try super floppy format. + * + * \param[in] dev The SdCard where the volume is located. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. reasons for + * failure include not finding a valid FAT16 file system, a call + * to init() after a volume has been successful initialized or + * an I/O error. + * + */ + static uint8_t init(SdCard* dev) { + return init(dev, 1) ? true : init(dev, 0); + } + /** + * Checks the file's open/closed status for this instance of Fat16. + * \return The value true if a file is open otherwise false; + */ + uint8_t isOpen(void) const {return (flags_ & O_ACCMODE) != 0;} + static void ls(uint8_t flags = 0); + uint8_t open(const char* fileName, uint8_t oflag); + uint8_t open(uint16_t entry, uint8_t oflag); + static void printDirName(const dir_t& dir, uint8_t width); + static void printFatDate(uint16_t fatDate); + static void printFatTime(uint16_t fatTime); + static void printTwoDigits(uint8_t v); + int16_t read(void); + int16_t read(void* buf, uint16_t nbyte); + static uint8_t readDir(dir_t* dir, uint16_t* index, + uint8_t skip = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY)); + + uint8_t remove(void); + static uint8_t remove(const char* fileName); + /** Sets the file's current position to zero. */ + void rewind(void) {curPosition_ = curCluster_ = 0;} + /** \return The number of entries in the root directory. */ + static uint16_t rootDirEntryCount(void) {return rootDirEntryCount_;} + /** Seek to current position plus \a pos bytes. See Fat16::seekSet(). */ + uint8_t seekCur(uint32_t pos) {return seekSet(curPosition_ + pos);} + /** Seek to end of file. See Fat16::seekSet(). */ + uint8_t seekEnd(void) {return seekSet(fileSize_);} + uint8_t seekSet(uint32_t pos); + uint8_t sync(void); + uint8_t timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day, + uint8_t hour, uint8_t minute, uint8_t second); + uint8_t truncate(uint32_t size); + /** Fat16::writeError is set to true if an error occurs during a write(). + * Set Fat16::writeError to false before calling print() and/or write() and check + * for true after calls to write() and/or print(). + */ + bool writeError; + int16_t write(const void *buf, uint16_t nbyte); + void write(uint8_t b); + void write(const char* str); + void write_P(PGM_P str); + void writeln_P(PGM_P str); +//------------------------------------------------------------------------------ +#if FAT16_DEBUG_SUPPORT + /** For debug only. Do not use in applications. */ + static cache16_t* dbgBufAdd(void) {return &cacheBuffer_;} + /** For debug only. Do not use in applications. */ + static void dbgSetDev(SdCard* dev) {rawDev_ = dev;} + /** For debug only. Do not use in applications. */ + static uint8_t* dbgCacheBlock(uint32_t blockNumber) { + return cacheRawBlock(blockNumber) ? cacheBuffer_.data : 0; } + /** For debug only. Do not use in applications. */ + static dir_t* dbgCacheDir(uint16_t index) { + return cacheDirEntry(index);} +#endif // FAT16_DEBUG_SUPPORT +//------------------------------------------------------------------------------ +#if ALLOW_DEPRECATED_FUNCTIONS +// Deprecated functions - suppress cpplint messages with NOLINT comment + public: + /** + * Deprecated - Use: + * static void Fat16::dateTimeCallback( + * void (*dateTime)(uint16_t* date, uint16_t* time)); + */ + static void dateTimeCallback( + void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT + oldDateTime_ = dateTime; + dateTime_ = dateTime ? oldToNew : 0; + } + /** Deprecated - Use: uint8_t Fat16::dirEntry(dir_t* dir); */ + uint8_t dirEntry(dir_t& dir) { // NOLINT + return dirEntry(&dir); + } + /** Deprecated - Use: static uint8_t Fat16::init(SdCard *dev); */ + static uint8_t init(SdCard& dev) {return init(&dev);} // NOLINT + + /** Deprecated - Use: static uint8_t Fat16::init(SdCard *dev, uint8_t part) */ + static uint8_t init(SdCard& dev, uint8_t part) { // NOLINT + return init(&dev, part); + } + /** + * Deprecated - Use: + * uint8_t Fat16::readDir(dir_t* dir, uint16_t* index, uint8_t skip); + */ + static uint8_t readDir(dir_t& dir, uint16_t& index, // NOLINT + uint8_t skip = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY)) { + return readDir(&dir, &index, skip); + } +//------------------------------------------------------------------------------ + private: + static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT + static void oldToNew(uint16_t *date, uint16_t *time) { + uint16_t d; + uint16_t t; + oldDateTime_(d, t); + *date = d; + *time = t; + } +#endif // ALLOW_DEPRECATED_FUNCTIONS +//------------------------------------------------------------------------------ + private: + // Volume info + static uint8_t volumeInitialized_; // true if volume has been initialized + static uint8_t fatCount_; // number of FATs + static uint8_t blocksPerCluster_; // must be power of 2 + static uint16_t rootDirEntryCount_; // should be 512 for FAT16 + static fat_t blocksPerFat_; // number of blocks in one FAT + static fat_t clusterCount_; // total clusters in volume + static uint32_t fatStartBlock_; // start of first FAT + static uint32_t rootDirStartBlock_; // start of root dir + static uint32_t dataStartBlock_; // start of data clusters + + // block cache + static uint8_t const CACHE_FOR_READ = 0; // cache a block for read + static uint8_t const CACHE_FOR_WRITE = 1; // cache a block and set dirty + static SdCard *rawDev_; // Device + static cache16_t cacheBuffer_; // 512 byte cache for raw blocks + static uint32_t cacheBlockNumber_; // Logical number of block in the cache + static uint8_t cacheDirty_; // cacheFlush() will write block if true + static uint32_t cacheMirrorBlock_; // mirror block for second FAT + + // callback function for date/time + static void (*dateTime_)(uint16_t* date, uint16_t* time); + + // define fields in flags_ + static uint8_t const F_OFLAG = O_ACCMODE | O_APPEND | O_SYNC; + static uint8_t const F_FILE_DIR_DIRTY = 0X80; // require sync directory entry + + uint8_t flags_; // see above for bit definitions + int16_t dirEntryIndex_; // index of directory entry for open file + fat_t firstCluster_; // first cluster of file + uint32_t fileSize_; // fileSize + fat_t curCluster_; // current cluster + uint32_t curPosition_; // current byte offset + + // private functions for cache + static uint8_t blockOfCluster(uint32_t position) { + // depends on blocks per cluster being power of two + return (position >> 9) & (blocksPerCluster_ - 1); + } + static uint16_t cacheDataOffset(uint32_t position) {return position & 0X1FF;} + static dir_t* cacheDirEntry(uint16_t index, uint8_t action = 0); + static uint8_t cacheRawBlock(uint32_t blockNumber, uint8_t action = 0); + static uint8_t cacheFlush(void); + static void cacheSetDirty(void) {cacheDirty_ |= CACHE_FOR_WRITE;} + static uint32_t dataBlockLba(fat_t cluster, uint8_t blockOfCluster) { + return dataStartBlock_ + (uint32_t)(cluster - 2) * blocksPerCluster_ + + blockOfCluster; + } + static uint8_t fatGet(fat_t cluster, fat_t* value); + static uint8_t fatPut(fat_t cluster, fat_t value); + // end of chain test + static uint8_t isEOC(fat_t cluster) {return cluster >= 0XFFF8;} + // allocate a cluster to a file + uint8_t addCluster(void); + // free a cluster chain + uint8_t freeChain(fat_t cluster); +}; +#endif // Fat16_h diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/Fat16Config.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/Fat16Config.h new file mode 100644 index 0000000..d598b56 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/Fat16Config.h @@ -0,0 +1,38 @@ +/* Arduino FAT16 Library + * Copyright (C) 2008 by William Greiman + * + * This file is part of the Arduino FAT16 Library + * + * This Library 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 Library 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 the Arduino Fat16 Library. If not, see + * . + */ + /** + * \file + * Configuration file + */ +#ifndef Fat16Config_h +#define Fat16Config_h +/** + * Allow use of deprecated functions if non-zero + */ +#define ALLOW_DEPRECATED_FUNCTIONS 1 +/** + * SdCard::writeBlock will protect block zero if set non-zero + */ +#define SD_PROTECT_BLOCK_ZERO 1 +/** + * Set non-zero to allow access to Fat16 internals by cardInfo debug sketch + */ +#define FAT16_DEBUG_SUPPORT 1 +#endif // Fat16Config_h diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/Fat16mainpage.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/Fat16mainpage.h new file mode 100644 index 0000000..2c4f773 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/Fat16mainpage.h @@ -0,0 +1,208 @@ +/* Arduino FAT16 Library + * Copyright (C) 2008 by William Greiman + * + * This file is part of the Arduino FAT16 Library + * + * This Library 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 Library 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 the Arduino Fat16 Library. If not, see + * . + */ + +/** +\mainpage Arduino Fat16 Library +
Copyright © 2008 by William Greiman +
+ +\section Intro Introduction +The Arduino Fat16 Library is a minimal implementation of the FAT16 file system +on standard SD flash memory cards. Fat16 supports read, write, file +creation, deletion, and truncation. + +The Fat16 class only supports access to files in the root directory and only +supports short 8.3 names. Directory time and date fields for creation +and modification can be maintained by providing a date/time callback +function \link Fat16::dateTimeCallback() dateTimeCallback()\endlink +or calling \link Fat16::timestamp() timestamp()\endlink. + +Fat16 was designed to use the Arduino Print class which +allows files to be written with \link Print::print() print() \endlink and +\link Print::println() println()\endlink. + +\section comment Bugs and Comments + +If you wish to report bugs or have comments, send email to fat16lib@sbcglobal.net. + + +\section SDcard SD Cards + +Arduinos access SD cards using the cards SPI protocol. PCs, Macs, and +most consumer devices use the 4-bit parallel SD protocol. A card that +functions well on A PC or Mac may not work well on the Arduino. + +Most cards have good SPI read performance but cards vary widely in SPI +write performance. Write performance is limited by how efficiently the +card manages internal erase/remapping operations. The Arduino cannot +optimize writes to reduce erase operations because of its limit RAM. + +SanDisk cards generally have good write performance. They seem to have +more internal RAM buffering than other cards and therefore can limit +the number of flash erase operations that the Arduino forces due to its +limited RAM. + +Some Dane-Elec cards have a write speed that is only 20% as fast as +a good SanDisk card. + + +\section Hardware Hardware Configuration +Fat16 was developed using an Adafruit Industries + GPS Shield. + +The hardware interface to the SD card should not use a resistor based level +shifter. SdCard::init() sets the SPI bus frequency to 8 MHz which results in +signal rise times that are too slow for the edge detectors in many newer SD card +controllers when resistor voltage dividers are used. + +The 5 to 3.3 V level shifter for 5 V arduinos should be IC based like the +74HC4050N based circuit shown in the file SdLevel.png. The Adafruit Wave Shield +uses a 74AHC125N. Gravitech sells SD and MicroSD Card Adapters based on the +74LCX245. + +If you are using a resistor based level shifter and are having problems try +setting the SPI bus frequency to 4 MHz. This can be done by using +card.init(true) to initialize the SD card. + + +\section Fat16Class Fat16 Usage + +The class Fat16 is a minimal implementation of FAT16 on standard SD cards. +High Capacity SD cards, SDHC, are not supported. It should work on all +standard cards from 8MB to 2GB formatted with a FAT16 file system. + +\note + The Arduino Print class uses character +at a time writes so it was necessary to use a \link Fat16::sync() sync() \endlink +function to control when data is written to the SD card. + +\par +An application which writes to a file using \link Print::print() print()\endlink, +\link Print::println() println() \endlink +or \link Fat16::write write() \endlink must call \link Fat16::sync() sync() \endlink +at the appropriate time to force data and directory information to be written +to the SD Card. Data and directory information are also written to the SD card +when \link Fat16::close() close() \endlink is called. + +\par +Applications must use care calling \link Fat16::sync() sync() \endlink +since 2048 bytes of I/O is required to update file and +directory information. This includes writing the current data block, reading +the block that contains the directory entry for update, writing the directory +block back and reading back the current data block. + +Fat16 only supports access to files in the root directory and only supports +short 8.3 names. + +It is possible to open a file with two or more instances of Fat16. A file may +be corrupted if data is written to the file by more than one instance of Fat16. + +Short names are limited to 8 characters followed by an optional period (.) +and extension of up to 3 characters. The characters may be any combination +of letters and digits. The following special characters are also allowed: + +$ % ' - _ @ ~ ` ! ( ) { } ^ # & + +Short names are always converted to upper case and their original case +value is lost. + +Fat16 uses a slightly restricted form of short names. +Only printable ASCII characters are supported. No characters with code point +values greater than 127 are allowed. Space is not allowed even though space +was allowed in the API of early versions of DOS. + +Fat16 has been optimized for The Arduino ATmega168. Minimizing RAM use is the +highest priority goal followed by flash use and finally performance. +Most SD cards only support 512 byte block write operations so a 512 byte +cache buffer is used by Fat16. This is the main use of RAM. A small +amount of RAM is used to store key volume and file information. +Flash memory usage can be controlled by selecting options in Fat16Config.h. + +\section HowTo How to format SD Cards as FAT16 Volumes + +Microsoft operating systems support removable media formatted with a +Master Boot Record, MBR, or formatted as a super floppy with a FAT Boot Sector +in block zero. + +Microsoft operating systems expect MBR formatted removable media +to have only one partition. The first partition should be used. + +Microsoft operating systems do not support partitioning SD flash cards. +If you erase an SD card with a program like KillDisk, Most versions of +Windows will format the card as a super floppy. + +The best way to restore an SD card's MBR is to use SDFormatter +which can be downloaded from: + +http://www.sdcard.org/consumers/formatter/ + +SDFormatter does not have an option for FAT type so it may format +small cards as FAT12. + +After the MBR is restored by SDFormatter you may need to reformat small +cards that have been formatted FAT12 to force the volume type to be FAT16. + +The FAT type, FAT12, FAT16, or FAT32, is determined by the count +of clusters on the volume and nothing else. + +Microsoft published the following code for determining FAT type: + +\code +if (CountOfClusters < 4085) { + // Volume is FAT12 +} +else if (CountOfClusters < 65525) { + // Volume is FAT16 +} +else { + // Volume is FAT32 +} + +\endcode +If you format a FAT volume with an OS utility , choose a cluster size that +will result in: + +4084 < CountOfClusters && CountOfClusters < 65525 + +The volume will then be FAT16. + +If you are formatting an SD card on OS X or Linux, be sure to use the first +partition. Format this partition with a cluster count in above range. + +\section References References + +The Arduino site: + +http://www.arduino.cc/ + +For more information about FAT file systems see: + +http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx + +For information about using SD cards as SPI devices see: + +http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf + +The ATmega328 datasheet: + +http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf + + + */ \ No newline at end of file diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/Fat16util.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/Fat16util.h new file mode 100644 index 0000000..a285aea --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/Fat16util.h @@ -0,0 +1,70 @@ +#ifndef Fat16util_h +#define Fat16util_h +/* Arduino FAT16 Library + * Copyright (C) 2008 by William Greiman + * + * This file is part of the Arduino FAT16 Library + * + * This Library 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 Library 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 the Arduino Fat16 Library. If not, see + * . + */ +/** + * \file + * Useful utility functions. + */ +#include +#include +/** Store and print a string in flash memory.*/ +#define PgmPrint(x) SerialPrint_P(PSTR(x)) +/** Store and print a string in flash memory followed by a CR/LF.*/ +#define PgmPrintln(x) SerialPrintln_P(PSTR(x)) +/** Defined so doxygen works for function definitions. */ +#define NOINLINE __attribute__((noinline)) +//------------------------------------------------------------------------------ +/** Return the number of bytes currently free in RAM. */ +static int FreeRam(void) { + extern int __bss_end; + extern int* __brkval; + int free_memory; + if (reinterpret_cast(__brkval) == 0) { + // if no heap use from end of bss section + free_memory = reinterpret_cast(&free_memory) + - reinterpret_cast(&__bss_end); + } else { + // use from top of stack to heap + free_memory = reinterpret_cast(&free_memory) + - reinterpret_cast(__brkval); + } + return free_memory; +} +//------------------------------------------------------------------------------ +/** + * %Print a string in flash memory to the serial port. + * + * \param[in] str Pointer to string stored in flash memory. + */ +static NOINLINE void SerialPrint_P(PGM_P str) { + for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.print(c); +} +//------------------------------------------------------------------------------ +/** + * %Print a string in flash memory followed by a CR/LF. + * + * \param[in] str Pointer to string stored in flash memory. + */ +static NOINLINE void SerialPrintln_P(PGM_P str) { + SerialPrint_P(str); + Serial.println(); +} +#endif // #define Fat16util_h diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/FatStructs.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/FatStructs.h new file mode 100644 index 0000000..431bf30 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/FatStructs.h @@ -0,0 +1,418 @@ +/* Arduino Fat16 Library + * Copyright (C) 2009 by William Greiman + * + * This file is part of the Arduino Fat16 Library + * + * This Library 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 Library 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 the Arduino Fat16 Library. If not, see + * . + */ +#ifndef FatStructs_h +#define FatStructs_h +/** + * \file + * FAT file structures + */ +/* + * mostly from Microsoft document fatgen103.doc + * http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx + */ +//------------------------------------------------------------------------------ +/** Value for byte 510 of boot block or MBR */ +uint8_t const BOOTSIG0 = 0X55; +/** Value for byte 511 of boot block or MBR */ +uint8_t const BOOTSIG1 = 0XAA; +//------------------------------------------------------------------------------ +/** + * \struct partitionTable + * \brief MBR partition table entry + * + * A partition table entry for a MBR formatted storage device. + * The MBR partition table has four entries. + */ +struct partitionTable { + /** + * Boot Indicator . Indicates whether the volume is the active + * partition. Legal values include: 0X00. Do not use for booting. + * 0X80 Active partition. + */ + uint8_t boot; + /** + * Head part of Cylinder-head-sector address of the first block in + * the partition. Legal values are 0-255. Only used in old PC BIOS. + */ + uint8_t beginHead; + /** + * Sector part of Cylinder-head-sector address of the first block in + * the partition. Legal values are 1-63. Only used in old PC BIOS. + */ + unsigned beginSector : 6; + /** High bits cylinder for first block in partition. */ + unsigned beginCylinderHigh : 2; + /** + * Combine beginCylinderLow with beginCylinderHigh. Legal values + * are 0-1023. Only used in old PC BIOS. + */ + uint8_t beginCylinderLow; + /** + * Partition type. See defines that begin with PART_TYPE_ for + * some Microsoft partition types. + */ + uint8_t type; + /** + * head part of cylinder-head-sector address of the last sector in the + * partition. Legal values are 0-255. Only used in old PC BIOS. + */ + uint8_t endHead; + /** + * Sector part of cylinder-head-sector address of the last sector in + * the partition. Legal values are 1-63. Only used in old PC BIOS. + */ + unsigned endSector : 6; + /** High bits of end cylinder */ + unsigned endCylinderHigh : 2; + /** + * Combine endCylinderLow with endCylinderHigh. Legal values + * are 0-1023. Only used in old PC BIOS. + */ + uint8_t endCylinderLow; + /** Logical block address of the first block in the partition. */ + uint32_t firstSector; + /** Length of the partition, in blocks. */ + uint32_t totalSectors; +}; +/** Type name for partitionTable */ +typedef struct partitionTable part_t; +//------------------------------------------------------------------------------ +/** + * \struct masterBootRecord + * + * \brief Master Boot Record + * + * The first block of a storage device that is formatted with a MBR. + */ +struct masterBootRecord { + /** Code Area for master boot program. */ + uint8_t codeArea[440]; + /** Optional WindowsNT disk signature. May contain more boot code. */ + uint32_t diskSignature; + /** Usually zero but may be more boot code. */ + uint16_t usuallyZero; + /** Partition tables. */ + part_t part[4]; + /** First MBR signature byte. Must be 0X55 */ + uint8_t mbrSig0; + /** Second MBR signature byte. Must be 0XAA */ + uint8_t mbrSig1; +}; +/** Type name for masterBootRecord */ +typedef struct masterBootRecord mbr_t; +//------------------------------------------------------------------------------ +/** + * \struct biosParmBlock + * + * \brief BIOS parameter block + * + * The BIOS parameter block describes the physical layout of a FAT volume. + */ +struct biosParmBlock { + /** + * Count of bytes per sector. This value may take on only the + * following values: 512, 1024, 2048 or 4096 + */ + uint16_t bytesPerSector; + /** + * Number of sectors per allocation unit. This value must be a + * power of 2 that is greater than 0. The legal values are + * 1, 2, 4, 8, 16, 32, 64, and 128. + */ + uint8_t sectorsPerCluster; + /** + * Number of sectors before the first FAT. + * This value must not be zero. + */ + uint16_t reservedSectorCount; + /** The count of FAT data structures on the volume. This field should + * always contain the value 2 for any FAT volume of any type. + */ + uint8_t fatCount; + /** + * For FAT12 and FAT16 volumes, this field contains the count of + * 32-byte directory entries in the root directory. For FAT32 volumes, + * this field must be set to 0. For FAT12 and FAT16 volumes, this + * value should always specify a count that when multiplied by 32 + * results in a multiple of bytesPerSector. FAT16 volumes should + * use the value 512. + */ + uint16_t rootDirEntryCount; + /** + * This field is the old 16-bit total count of sectors on the volume. + * This count includes the count of all sectors in all four regions + * of the volume. This field can be 0; if it is 0, then totalSectors32 + * must be non-zero. For FAT32 volumes, this field must be 0. For + * FAT12 and FAT16 volumes, this field contains the sector count, and + * totalSectors32 is 0 if the total sector count fits + * (is less than 0x10000). + */ + uint16_t totalSectors16; + /** + * This dates back to the old MS-DOS 1.x media determination and is + * no longer usually used for anything. 0xF8 is the standard value + * for fixed (non-removable) media. For removable media, 0xF0 is + * frequently used. Legal values are 0xF0 or 0xF8-0xFF. + */ + uint8_t mediaType; + /** + * Count of sectors occupied by one FAT on FAT12/FAT16 volumes. + * On FAT32 volumes this field must be 0, and sectorsPerFat32 + * contains the FAT size count. + */ + uint16_t sectorsPerFat16; + /** Sectors per track for interrupt 0x13. Not used otherwise. */ + uint16_t sectorsPerTrtack; + /** Number of heads for interrupt 0x13. Not used otherwise. */ + uint16_t headCount; + /** + * Count of hidden sectors preceding the partition that contains this + * FAT volume. This field is generally only relevant for media + * visible on interrupt 0x13. + */ + uint32_t hidddenSectors; + /** + * This field is the new 32-bit total count of sectors on the volume. + * This count includes the count of all sectors in all four regions + * of the volume. This field can be 0; if it is 0, then + * totalSectors16 must be non-zero. + */ + uint32_t totalSectors32; + /** + * Count of sectors occupied by one FAT on FAT32 volumes. + */ + uint32_t sectorsPerFat32; + /** + * This field is only defined for FAT32 media and does not exist on + * FAT12 and FAT16 media. + * Bits 0-3 -- Zero-based number of active FAT. + * Only valid if mirroring is disabled. + * Bits 4-6 -- Reserved. + * Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs. + * -- 1 means only one FAT is active; it is the one referenced in bits 0-3. + * Bits 8-15 -- Reserved. + */ + uint16_t fat32Flags; + /** + * FAT32 version. High byte is major revision number. + * Low byte is minor revision number. Only 0.0 define. + */ + uint16_t fat32Version; + /** + * Cluster number of the first cluster of the root directory for FAT32. + * This usually 2 but not required to be 2. + */ + uint32_t fat32RootCluster; + /** + * Sector number of FSINFO structure in the reserved area of the + * FAT32 volume. Usually 1. + */ + uint16_t fat32FSInfo; + /** + * If non-zero, indicates the sector number in the reserved area + * of the volume of a copy of the boot record. Usually 6. + * No value other than 6 is recommended. + */ + uint16_t fat32BackBootBlock; + /** + * Reserved for future expansion. Code that formats FAT32 volumes + * should always set all of the bytes of this field to 0. + */ + uint8_t fat32Reserved[12]; +}; +/** Type name for biosParmBlock */ +typedef struct biosParmBlock bpb_t; +//------------------------------------------------------------------------------ +/** + * \struct fat32BootSector + * + * \brief Boot sector for a FAT16 or FAT32 volume. + * + */ +struct fat32BootSector { + /** X86 jmp to boot program */ + uint8_t jmpToBootCode[3]; + /** informational only - don't depend on it */ + char oemName[8]; + /** BIOS Parameter Block */ + bpb_t bpb; + /** for int0x13 use value 0X80 for hard drive */ + uint8_t driveNumber; + /** used by Windows NT - should be zero for FAT */ + uint8_t reserved1; + /** 0X29 if next three fields are valid */ + uint8_t bootSignature; + /** usually generated by combining date and time */ + uint32_t volumeSerialNumber; + /** should match volume label in root dir */ + char volumeLabel[11]; + /** informational only - don't depend on it */ + char fileSystemType[8]; + /** X86 boot code */ + uint8_t bootCode[420]; + /** must be 0X55 */ + uint8_t bootSectorSig0; + /** must be 0XAA */ + uint8_t bootSectorSig1; +}; +//------------------------------------------------------------------------------ +// End Of Chain values for FAT entries +/** FAT16 end of chain value used by Microsoft. */ +uint16_t const FAT16EOC = 0XFFFF; +/** Minimum value for FAT16 EOC. Use to test for EOC. */ +uint16_t const FAT16EOC_MIN = 0XFFF8; +/** FAT32 end of chain value used by Microsoft. */ +uint32_t const FAT32EOC = 0X0FFFFFFF; +/** Minimum value for FAT32 EOC. Use to test for EOC. */ +uint32_t const FAT32EOC_MIN = 0X0FFFFFF8; +/** Mask a for FAT32 entry. Entries are 28 bits. */ +uint32_t const FAT32MASK = 0X0FFFFFFF; + +/** Type name for fat32BootSector */ +typedef struct fat32BootSector fbs_t; +//------------------------------------------------------------------------------ +/** + * \struct directoryEntry + * \brief FAT short directory entry + * + * Short means short 8.3 name, not the entry size. + * + * Date Format. A FAT directory entry date stamp is a 16-bit field that is + * basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the + * format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the + * 16-bit word): + * + * Bits 9-15: Count of years from 1980, valid value range 0-127 + * inclusive (1980-2107). + * + * Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive. + * + * Bits 0-4: Day of month, valid value range 1-31 inclusive. + * + * Time Format. A FAT directory entry time stamp is a 16-bit field that has + * a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the + * 16-bit word, bit 15 is the MSB of the 16-bit word). + * + * Bits 11-15: Hours, valid value range 0-23 inclusive. + * + * Bits 5-10: Minutes, valid value range 0-59 inclusive. + * + * Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds). + * + * The valid time range is from Midnight 00:00:00 to 23:59:58. + */ +struct directoryEntry { + /** + * Short 8.3 name. + * The first eight bytes contain the file name with blank fill. + * The last three bytes contain the file extension with blank fill. + */ + uint8_t name[11]; + /** Entry attributes. + * + * The upper two bits of the attribute byte are reserved and should + * always be set to 0 when a file is created and never modified or + * looked at after that. See defines that begin with DIR_ATT_. + */ + uint8_t attributes; + /** + * Reserved for use by Windows NT. Set value to 0 when a file is + * created and never modify or look at it after that. + */ + uint8_t reservedNT; + /** + * The granularity of the seconds part of creationTime is 2 seconds + * so this field is a count of tenths of a second and its valid + * value range is 0-199 inclusive. (WHG note - seems to be hundredths) + */ + uint8_t creationTimeTenths; + /** Time file was created. */ + uint16_t creationTime; + /** Date file was created. */ + uint16_t creationDate; + /** + * Last access date. Note that there is no last access time, only + * a date. This is the date of last read or write. In the case of + * a write, this should be set to the same date as lastWriteDate. + */ + uint16_t lastAccessDate; + /** + * High word of this entry's first cluster number (always 0 for a + * FAT12 or FAT16 volume). + */ + uint16_t firstClusterHigh; + /** Time of last write. File creation is considered a write. */ + uint16_t lastWriteTime; + /** Date of last write. File creation is considered a write. */ + uint16_t lastWriteDate; + /** Low word of this entry's first cluster number. */ + uint16_t firstClusterLow; + /** 32-bit unsigned holding this file's size in bytes. */ + uint32_t fileSize; +}; +//------------------------------------------------------------------------------ +// Definitions for directory entries +// +/** Type name for directoryEntry */ +typedef struct directoryEntry dir_t; +/** escape for name[0] = 0XE5 */ +uint8_t const DIR_NAME_0XE5 = 0X05; +/** name[0] value for entry that is free after being "deleted" */ +uint8_t const DIR_NAME_DELETED = 0XE5; +/** name[0] value for entry that is free and no allocated entries follow */ +uint8_t const DIR_NAME_FREE = 0X00; +/** file is read-only */ +uint8_t const DIR_ATT_READ_ONLY = 0X01; +/** File should hidden in directory listings */ +uint8_t const DIR_ATT_HIDDEN = 0X02; +/** Entry is for a system file */ +uint8_t const DIR_ATT_SYSTEM = 0X04; +/** Directory entry contains the volume label */ +uint8_t const DIR_ATT_VOLUME_ID = 0X08; +/** Entry is for a directory */ +uint8_t const DIR_ATT_DIRECTORY = 0X10; +/** Old DOS archive bit for backup support */ +uint8_t const DIR_ATT_ARCHIVE = 0X20; +/** Test value for long name entry. Test is + (d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */ +uint8_t const DIR_ATT_LONG_NAME = 0X0F; +/** Test mask for long name entry */ +uint8_t const DIR_ATT_LONG_NAME_MASK = 0X3F; +/** defined attribute bits */ +uint8_t const DIR_ATT_DEFINED_BITS = 0X3F; +/** Directory entry is part of a long name */ +static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) { + return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME; +} +/** Mask for file/subdirectory tests */ +uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY); +/** Directory entry is for a file */ +static inline uint8_t DIR_IS_FILE(const dir_t* dir) { + return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0; +} +/** Directory entry is for a subdirectory */ +static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) { + return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY; +} +/** Directory entry is for a file or subdirectory */ +static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) { + return (dir->attributes & DIR_ATT_VOLUME_ID) == 0; +} +#endif // FatStructs_h diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/SdCard.cpp b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/SdCard.cpp new file mode 100644 index 0000000..0bb277a --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/SdCard.cpp @@ -0,0 +1,268 @@ +/* Arduino FAT16 Library + * Copyright (C) 2008 by William Greiman + * + * This file is part of the Arduino FAT16 Library + * + * This Library 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 Library 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 the Arduino Fat16 Library. If not, see + * . + */ +#include +#include "Fat16Config.h" +#include "SdCard.h" +//------------------------------------------------------------------------------ +// r1 status values +uint8_t const R1_READY_STATE = 0; +uint8_t const R1_IDLE_STATE = 1; +// start data token for read or write +uint8_t const DATA_START_BLOCK = 0XFE; +// data response tokens for write block +uint8_t const DATA_RES_MASK = 0X1F; +uint8_t const DATA_RES_ACCEPTED = 0X05; +uint8_t const DATA_RES_CRC_ERROR = 0X0B; +uint8_t const DATA_RES_WRITE_ERROR = 0X0D; +// +// stop compiler from inlining where speed optimization is not required +#define STATIC_NOINLINE static __attribute__((noinline)) +//------------------------------------------------------------------------------ +// SPI static functions +// +// clock byte in +STATIC_NOINLINE uint8_t spiRec(void) { + SPDR = 0xff; + while (!(SPSR & (1 << SPIF))); + return SPDR; +} +// clock byte out +STATIC_NOINLINE void spiSend(uint8_t b) { + SPDR = b; + while (!(SPSR & (1 << SPIF))); +} +//------------------------------------------------------------------------------ +// wait for card to go not busy +// return false if timeout +static uint8_t waitForToken(uint8_t token, uint16_t timeoutMillis) { + uint16_t t0 = millis(); + while (spiRec() != token) { + if (((uint16_t)millis() - t0) > timeoutMillis) return false; + } + return true; +} +//------------------------------------------------------------------------------ +uint8_t SdCard::cardCommand(uint8_t cmd, uint32_t arg) { + uint8_t r1; + + // select card + chipSelectLow(); + + // wait if busy + waitForToken(0XFF, SD_COMMAND_TIMEOUT); + + // send command + spiSend(cmd | 0x40); + + // send argument + for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); + + // send CRC - must send valid CRC for CMD0 + spiSend(cmd == CMD0 ? 0x95 : 0XFF); + + // wait for not busy + for (uint8_t retry = 0; (0X80 & (r1 = spiRec())) && retry != 0XFF; retry++); + return r1; +} +//------------------------------------------------------------------------------ +uint8_t SdCard::cardAcmd(uint8_t cmd, uint32_t arg) { + cardCommand(CMD55, 0); + return cardCommand(cmd, arg); +} +//============================================================================== +// SdCard member functions +//------------------------------------------------------------------------------ +/** + * Determine the size of a standard SD flash memory card + * \return The number of 512 byte data blocks in the card + */ +uint32_t SdCard::cardSize(void) { + uint16_t c_size; + csd_t csd; + if (!readReg(CMD9, &csd)) return 0; + uint8_t read_bl_len = csd.read_bl_len; + c_size = (csd.c_size_high << 10) | (csd.c_size_mid << 2) | csd.c_size_low; + uint8_t c_size_mult = (csd.c_size_mult_high << 1) | csd.c_size_mult_low; + return (uint32_t)(c_size+1) << (c_size_mult + read_bl_len - 7); +} +//------------------------------------------------------------------------------ +void SdCard::chipSelectHigh(void) { + digitalWrite(chipSelectPin_, HIGH); +} +//------------------------------------------------------------------------------ +void SdCard::chipSelectLow(void) { + digitalWrite(chipSelectPin_, LOW); +} +//------------------------------------------------------------------------------ +void SdCard::error(uint8_t code, uint8_t data) { + errorData = data; + error(code); +} +//------------------------------------------------------------------------------ +void SdCard::error(uint8_t code) { + errorCode = code; + chipSelectHigh(); +} +//------------------------------------------------------------------------------ +/** + * Initialize a SD flash memory card. + * + * \param[in] speed Set SPI Frequency to F_CPU/2 if speed = 0 or F_CPU/4 + * if speed = 1. + * \param[in] chipSelectPin SD chip select pin number. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * + */ +uint8_t SdCard::init(uint8_t speed, uint8_t chipSelectPin) { + if (speed > 1) { + error(SD_ERROR_SPI_SPEED); + return false; + } + errorCode = 0; + chipSelectPin_ = chipSelectPin; + uint8_t r; + // 16-bit init start time allows over a minute + uint16_t t0 = (uint16_t)millis(); + + pinMode(chipSelectPin_, OUTPUT); + chipSelectHigh(); + pinMode(SPI_MISO_PIN, INPUT); + pinMode(SPI_SS_PIN, OUTPUT); + pinMode(SPI_MOSI_PIN, OUTPUT); + pinMode(SPI_SCK_PIN, OUTPUT); + + // Enable SPI, Master, clock rate F_CPU/128 + SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); + + // must supply min of 74 clock cycles with CS high. + for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); + chipSelectLow(); + + // command to go idle in SPI mode + while ((r = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { + if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { + error(SD_ERROR_CMD0, r); + return false; + } + } + // start initialization and wait for completed initialization + while ((r = cardAcmd(ACMD41, 0)) != R1_READY_STATE) { + if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { + error(SD_ERROR_ACMD41, r); + return false; + } + } + // set SPI frequency + SPCR &= ~((1 << SPR1) | (1 << SPR0)); // F_CPU/4 + if (!speed) SPSR |= (1 << SPI2X); // Doubled Clock Frequency to F_CPU/2 + chipSelectHigh(); + return true; +} +//------------------------------------------------------------------------------ +/** + * Reads a 512 byte block from a storage device. + * + * \param[in] blockNumber Logical block to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t SdCard::readBlock(uint32_t blockNumber, uint8_t* dst) { + if (cardCommand(CMD17, blockNumber << 9)) { + error(SD_ERROR_CMD17); + return false; + } + return readTransfer(dst, 512); +} +//------------------------------------------------------------------------------ +uint8_t SdCard::readReg(uint8_t cmd, void* buf) { + uint8_t* dst = reinterpret_cast(buf); + if (cardCommand(cmd, 0)) { + chipSelectHigh(); + return false; + } + return readTransfer(dst, 16); +} +//------------------------------------------------------------------------------ +uint8_t SdCard::readTransfer(uint8_t* dst, uint16_t count) { + // wait for start of data + if (!waitForToken(DATA_START_BLOCK, SD_READ_TIMEOUT)) { + error(SD_ERROR_READ_TIMEOUT); + } + // start first spi transfer + SPDR = 0XFF; + for (uint16_t i = 0; i < count; i++) { + while (!(SPSR & (1 << SPIF))); + dst[i] = SPDR; + SPDR = 0XFF; + } + // wait for first CRC byte + while (!(SPSR & (1 << SPIF))); + spiRec(); // second CRC byte + chipSelectHigh(); + return true; +} +//------------------------------------------------------------------------------ +/** + * Writes a 512 byte block to a storage device. + * + * \param[in] blockNumber Logical block to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t SdCard::writeBlock(uint32_t blockNumber, const uint8_t* src) { + uint32_t address = blockNumber << 9; +#if SD_PROTECT_BLOCK_ZERO + // don't allow write to first block + if (address == 0) { + error(SD_ERROR_BLOCK_ZERO_WRITE); + return false; + } +#endif // SD_PROTECT_BLOCK_ZERO + if (cardCommand(CMD24, address)) { + error(SD_ERROR_CMD24); + return false; + } + // optimize write loop + SPDR = DATA_START_BLOCK; + for (uint16_t i = 0; i < 512; i++) { + while (!(SPSR & (1 << SPIF))); + SPDR = src[i]; + } + while (!(SPSR & (1 << SPIF))); // wait for last data byte + spiSend(0xFF); // dummy crc + spiSend(0xFF); // dummy crc + + // get write response + uint8_t r1 = spiRec(); + if ((r1 & DATA_RES_MASK) != DATA_RES_ACCEPTED) { + error(SD_ERROR_WRITE_RESPONSE, r1); + return false; + } + // wait for card to complete write programming + if (!waitForToken(0XFF, SD_WRITE_TIMEOUT)) { + error(SD_ERROR_WRITE_TIMEOUT); + } + chipSelectHigh(); + return true; +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/SdCard.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/SdCard.h new file mode 100644 index 0000000..8fe5db3 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/SdCard.h @@ -0,0 +1,177 @@ +/* Arduino FAT16 Library + * Copyright (C) 2008 by William Greiman + * + * This file is part of the Arduino FAT16 Library + * + * This Library 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 Library 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 the Arduino Fat16 Library. If not, see + * . + */ +#ifndef SdCard_h +#define SdCard_h + /** + * \file + * SdCard class + */ +#include "SdInfo.h" +//------------------------------------------------------------------------------ +// Warning only SD_CHIP_SELECT_PIN, the SD card select pin, may be redefined. +// define hardware SPI pins +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +// pins for Arduino Mega +uint8_t const SPI_SS_PIN = 53; +uint8_t const SPI_MOSI_PIN = 51; +uint8_t const SPI_MISO_PIN = 50; +uint8_t const SPI_SCK_PIN = 52; +#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) +// pins for Sanguino +uint8_t const SPI_SS_PIN = 4; +uint8_t const SPI_MOSI_PIN = 5; +uint8_t const SPI_MISO_PIN = 6; +uint8_t const SPI_SCK_PIN = 7; +#elif defined(__AVR_ATmega32U4__) +// pins for Teensy 2.0 +uint8_t const SPI_SS_PIN = 0; +uint8_t const SPI_MOSI_PIN = 2; +uint8_t const SPI_MISO_PIN = 3; +uint8_t const SPI_SCK_PIN = 1; +#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) +// pins for Teensy++ 1.0 & 2.0 +uint8_t const SPI_SS_PIN = 20; +uint8_t const SPI_MOSI_PIN = 22; +uint8_t const SPI_MISO_PIN = 23; +uint8_t const SPI_SCK_PIN = 21; +#else // SPI pins +// pins for other Arduinos +/** Slave Select pin */ +uint8_t const SPI_SS_PIN = 10; +/** Master Out Slave In pin */ +uint8_t const SPI_MOSI_PIN = 11; +/** Master In Slave Out pin */ +uint8_t const SPI_MISO_PIN = 12; +/** Serial Clock */ +uint8_t const SPI_SCK_PIN = 13; +#endif // SPI pins +/** + * SD Chip Select pin + * + * Warning if this pin is redefined the hardware SS pin will be enabled + * as an output by init(). An avr processor will not function as an SPI + * master unless SS is set to output mode. + * + * For example to set SD_CHIP_SELECT_PIN to 8 for the SparkFun microSD shield: + * uint8_t const SD_CHIP_SELECT_PIN = 8; + * + * The default chip select pin for the SD card is SS. + */ +uint8_t const SD_CHIP_SELECT_PIN = SPI_SS_PIN; +//------------------------------------------------------------------------------ +/** command timeout ms */ +uint16_t const SD_COMMAND_TIMEOUT = 300; +/** init timeout ms */ +uint16_t const SD_INIT_TIMEOUT = 2000; +/** read timeout ms */ +uint16_t const SD_READ_TIMEOUT = 300; +/** write timeout ms */ +uint16_t const SD_WRITE_TIMEOUT = 600; +//------------------------------------------------------------------------------ +// error codes +/** Card did not go into SPI mode */ +uint8_t const SD_ERROR_CMD0 = 1; +/** Card did not go ready */ +uint8_t const SD_ERROR_ACMD41 = 2; +/** Write command not accepted */ +uint8_t const SD_ERROR_CMD24 = 3; +/** Read command not accepted */ +uint8_t const SD_ERROR_CMD17 = 4; +/** timeout waiting for read data */ +uint8_t const SD_ERROR_READ_TIMEOUT = 5; +/** write error occurred */ +uint8_t const SD_ERROR_WRITE_RESPONSE = 6; +/** timeout waiting for write status */ +uint8_t const SD_ERROR_WRITE_TIMEOUT = 7; +/** attempt to write block zero */ +uint8_t const SD_ERROR_BLOCK_ZERO_WRITE = 8; +/** card returned an error to a CMD13 status check after a write */ +uint8_t const SD_ERROR_WRITE_PROGRAMMING = 9; +/** invalid SPI speed in init() call */ +uint8_t const SD_ERROR_SPI_SPEED = 10; +//------------------------------------------------------------------------------ +// SD command codes +/** SEND OPERATING CONDITIONS */ +uint8_t const ACMD41 = 0X29; +/** GO_IDLE_STATE - init card in spi mode if CS low */ +uint8_t const CMD0 = 0X00; +/** SEND_CSD - Card Specific Data */ +uint8_t const CMD9 = 0X09; +/** SEND_CID - Card IDentification */ +uint8_t const CMD10 = 0X0A; +/** SEND_STATUS - read the card status register */ +uint8_t const CMD13 = 0X0D; +/** READ_BLOCK */ +uint8_t const CMD17 = 0X11; +/** WRITE_BLOCK */ +uint8_t const CMD24 = 0X18; +/** APP_CMD - escape for application specific command */ +uint8_t const CMD55 = 0X37; +//------------------------------------------------------------------------------ +/** + * \class SdCard + * \brief Hardware access class for SD flash cards + * + * Supports raw access to a standard SD flash memory card. + * + */ +class SdCard { + public: + /** Code for a SD error. See SdCard.h for definitions. */ + uint8_t errorCode; + /** Data that may be helpful in determining the cause of an error */ + uint8_t errorData; + uint32_t cardSize(void); + /** + * Initialize an SD flash memory card with default clock rate and chip + * select pin. See SdCard::init(uint8_t sckRateID, uint8_t chipSelectPin). + */ + uint8_t init(void) { + return init(0, SD_CHIP_SELECT_PIN); + } + /** + * Initialize an SD flash memory card with the selected SPI clock rate + * and the default SD chip select pin. + * See SdCard::init(uint8_t slow, uint8_t chipSelectPin). + */ + uint8_t init(uint8_t speed) { + return init(speed, SD_CHIP_SELECT_PIN); + } + uint8_t init(uint8_t speed, uint8_t chipselectPin); + uint8_t readBlock(uint32_t block, uint8_t* dst); + /** Read the CID register which contains info about the card. + * This includes Manufacturer ID, OEM ID, product name, version, + * serial number, and manufacturing date. */ + uint8_t readCID(cid_t* cid) { + return readReg(CMD10, cid); + } + uint8_t writeBlock(uint32_t block, const uint8_t* src); + private: + uint8_t cardAcmd(uint8_t cmd, uint32_t arg); + uint8_t cardCommand(uint8_t cmd, uint32_t arg); + uint8_t chipSelectPin_; + void chipSelectHigh(void); + void chipSelectLow(void); + void error(uint8_t code, uint8_t data); + void error(uint8_t code); + uint8_t readReg(uint8_t cmd, void* buf); + uint8_t readTransfer(uint8_t* dst, uint16_t count); +}; +#endif // SdCard_h diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/SdInfo.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/SdInfo.h new file mode 100644 index 0000000..4c82e0b --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/SdInfo.h @@ -0,0 +1,117 @@ +/* Arduino FAT16 Library + * Copyright (C) 2008 by William Greiman + * + * This file is part of the Arduino FAT16 Library + * + * This Library 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 Library 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 the Arduino Fat16 Library. If not, see + * . + */ +#ifndef SdInfo_h +#define SdInfo_h +#include +// Based on the document: +// +// SD Specifications +// Part 1 +// Physical Layer +// Simplified Specification +// Version 2.00 +// September 25, 2006 +// +// www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf +// +// Card IDentification (CID) register +typedef struct CID { + // byte 0 + uint8_t mid; // Manufacturer ID + // byte 1-2 + char oid[2]; // OEM/Application ID + // byte 3-7 + char pnm[5]; // Product name + // byte 8 + unsigned prv_m : 4; // Product revision n.m + unsigned prv_n : 4; + // byte 9-12 + uint32_t psn; // Product serial number + // byte 13 + unsigned mdt_year_high : 4; // Manufacturing date + unsigned reserved : 4; + // byte 14 + unsigned mdt_month : 4; + unsigned mdt_year_low :4; + // byte 15 + unsigned always1 : 1; + unsigned crc : 7; +}cid_t; +// Card-Specific Data register +typedef struct CSD { + // byte 0 + unsigned reserved1 : 6; + unsigned csd_ver : 2; + // byte 1 + uint8_t taac; + // byte 2 + uint8_t nsac; + // byte 3 + uint8_t tran_speed; + // byte 4 + uint8_t ccc_high; + // byte 5 + unsigned read_bl_len : 4; + unsigned ccc_low : 4; + // byte 6 + unsigned c_size_high : 2; + unsigned reserved2 : 2; + unsigned dsr_imp : 1; + unsigned read_blk_misalign :1; + unsigned write_blk_misalign : 1; + unsigned read_bl_partial : 1; + // byte 7 + uint8_t c_size_mid; + // byte 8 + unsigned vdd_r_curr_max : 3; + unsigned vdd_r_curr_min : 3; + unsigned c_size_low :2; + // byte 9 + unsigned c_size_mult_high : 2; + unsigned vdd_w_cur_max : 3; + unsigned vdd_w_curr_min : 3; + // byte 10 + unsigned sector_size_high : 6; + unsigned erase_blk_en : 1; + unsigned c_size_mult_low : 1; + // byte 11 + unsigned wp_grp_size : 7; + unsigned sector_size_low : 1; + // byte 12 + unsigned write_bl_len_high : 2; + unsigned r2w_factor : 3; + unsigned reserved3 : 2; + unsigned wp_grp_enable : 1; + // byte 13 + unsigned reserved4 : 5; + unsigned write_partial : 1; + unsigned write_bl_len_low : 2; + // byte 14 + unsigned reserved5: 2; + unsigned file_format : 2; + unsigned tmp_write_protect : 1; + unsigned perm_write_protect : 1; + unsigned copy : 1; + unsigned file_format_grp : 1; + // byte 15 + unsigned always1 : 1; + unsigned crc : 7; +}csd_t; +#endif // SdInfo_h diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/clean.bat b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/clean.bat new file mode 100644 index 0000000..9b94e7f --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/clean.bat @@ -0,0 +1,2 @@ +rm -r */applet +pause \ No newline at end of file diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16AnalogLogger/fat16AnalogLogger.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16AnalogLogger/fat16AnalogLogger.pde new file mode 100644 index 0000000..cbe08e4 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16AnalogLogger/fat16AnalogLogger.pde @@ -0,0 +1,120 @@ +// A simple data logger for the analog pins +#define LOG_INTERVAL 1000 // mills between entries +#define SENSOR_COUNT 3 // number of analog pins to log +#define ECHO_TO_SERIAL 1 // echo data to serial port +#define WAIT_TO_START 1 // Wait for serial input in setup() +#define SYNC_INTERVAL 1000 // mills between calls to sync() +uint32_t syncTime = 0; // time of last sync() +uint32_t logTime = 0; // time data was logged + +#include +#include // use functions to print strings from flash memory + +SdCard card; +Fat16 file; + +// store error strings in flash to save RAM +#define error(s) error_P(PSTR(s)) + +void error_P(const char* str) { + PgmPrint("error: "); + SerialPrintln_P(str); + if (card.errorCode) { + PgmPrint("SD error: "); + Serial.println(card.errorCode, HEX); + } + while(1); +} + +void setup(void) { + Serial.begin(9600); + Serial.println(); + +#if WAIT_TO_START + PgmPrintln("Type any character to start"); + while (!Serial.available()); +#endif //WAIT_TO_START + + // initialize the SD card + if (!card.init()) error("card.init"); + + // initialize a FAT16 volume + if (!Fat16::init(&card)) error("Fat16::init"); + + // create a new file + char name[] = "LOGGER00.CSV"; + for (uint8_t i = 0; i < 100; i++) { + name[6] = i/10 + '0'; + name[7] = i%10 + '0'; + // O_CREAT - create the file if it does not exist + // O_EXCL - fail if the file exists + // O_WRITE - open for write only + if (file.open(name, O_CREAT | O_EXCL | O_WRITE))break; + } + if (!file.isOpen()) error ("create"); + PgmPrint("Logging to: "); + Serial.println(name); + + // write data header + + // clear write error + file.writeError = false; + file.print("millis"); +#if ECHO_TO_SERIAL + Serial.print("millis"); +#endif //ECHO_TO_SERIAL + +#if SENSOR_COUNT > 6 +#error SENSOR_COUNT too large +#endif //SENSOR_COUNT + + for (uint8_t i = 0; i < SENSOR_COUNT; i++) { + file.print(",sens");file.print(i, DEC); +#if ECHO_TO_SERIAL + Serial.print(",sens");Serial.print(i, DEC); +#endif //ECHO_TO_SERIAL + } + file.println(); +#if ECHO_TO_SERIAL + Serial.println(); +#endif //ECHO_TO_SERIAL + + if (file.writeError || !file.sync()) { + error("write header"); + } +} + +void loop() { // run over and over again + uint32_t m = logTime; + // wait till time is an exact multiple of LOG_INTERVAL + do { + logTime = millis(); + } while (m == logTime || logTime % LOG_INTERVAL); + // log time to file + file.print(logTime); +#if ECHO_TO_SERIAL + Serial.print(logTime); +#endif //ECHO_TO_SERIAL + + // add sensor data + for (uint8_t ia = 0; ia < SENSOR_COUNT; ia++) { + uint16_t data = analogRead(ia); + file.print(','); + file.print(data); +#if ECHO_TO_SERIAL + Serial.print(','); + Serial.print(data); +#endif //ECHO_TO_SERIAL + } + file.println(); +#if ECHO_TO_SERIAL + Serial.println(); +#endif //ECHO_TO_SERIAL + + if (file.writeError) error("write data"); + + //don't sync too often - requires 2048 bytes of I/O to SD card + if ((millis() - syncTime) < SYNC_INTERVAL) return; + syncTime = millis(); + if (!file.sync()) error("sync"); +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16GPSLogger_v3/fat16GPSLogger_v3.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16GPSLogger_v3/fat16GPSLogger_v3.pde new file mode 100644 index 0000000..e09552c --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16GPSLogger_v3/fat16GPSLogger_v3.pde @@ -0,0 +1,328 @@ +// Ladyada's logger modified by Bill Greiman to use the Fat16 library + +// this is a generic logger that does checksum testing so the data written should be always good +// Assumes a sirf III chipset logger attached to pin 0 and 1 + +#include +#include +#include + +// macros to use PSTR +#define putstring(str) SerialPrint_P(PSTR(str)) +#define putstring_nl(str) SerialPrintln_P(PSTR(str)) + +// power saving modes +#define SLEEPDELAY 0 +#define TURNOFFGPS 0 +#define LOG_RMC_FIXONLY 1 + +SdCard card; +Fat16 f; + +#define led1Pin 4 +#define led2Pin 3 +#define powerPin 2 + +#define BUFFSIZE 75 +char buffer[BUFFSIZE]; +uint8_t bufferidx = 0; +uint8_t fix = 0; // current fix data +uint8_t i; + +/* EXAMPLE + +$PSRF103,,,,*CKSUM + + 00=GGA,01=GLL,02=GSA,03=GSV,04=RMC,05=VTG + 00=SetRate,01=Query + Output every seconds, off=00,max=255 + 00=disable Checksum,01=Enable checksum for specified message +Note: checksum is required + +Example 1: Query the GGA message with checksum enabled +$PSRF103,00,01,00,01*25 + +Example 2: Enable VTG message for a 1Hz constant output with checksum enabled +$PSRF103,05,00,01,01*20 + +Example 3: Disable VTG message +$PSRF103,05,00,00,01*21 + +*/ + +#define SERIAL_SET "$PSRF100,01,4800,08,01,00*0E\r\n" + +// GGA-Global Positioning System Fixed Data, message 103,00 +#define LOG_GGA 0 +#define GGA_ON "$PSRF103,00,00,01,01*25\r\n" +#define GGA_OFF "$PSRF103,00,00,00,01*24\r\n" + +// GLL-Geographic Position-Latitude/Longitude, message 103,01 +#define LOG_GLL 0 +#define GLL_ON "$PSRF103,01,00,01,01*26\r\n" +#define GLL_OFF "$PSRF103,01,00,00,01*27\r\n" + +// GSA-GNSS DOP and Active Satellites, message 103,02 +#define LOG_GSA 0 +#define GSA_ON "$PSRF103,02,00,01,01*27\r\n" +#define GSA_OFF "$PSRF103,02,00,00,01*26\r\n" + +// GSV-GNSS Satellites in View, message 103,03 +#define LOG_GSV 0 +#define GSV_ON "$PSRF103,03,00,01,01*26\r\n" +#define GSV_OFF "$PSRF103,03,00,00,01*27\r\n" + +// RMC-Recommended Minimum Specific GNSS Data, message 103,04 +#define LOG_RMC 1 +#define RMC_ON "$PSRF103,04,00,01,01*21\r\n" +#define RMC_OFF "$PSRF103,04,00,00,01*20\r\n" + +// VTG-Course Over Ground and Ground Speed, message 103,05 +#define LOG_VTG 0 +#define VTG_ON "$PSRF103,05,00,01,01*20\r\n" +#define VTG_OFF "$PSRF103,05,00,00,01*21\r\n" + +// Switch Development Data Messages On/Off, message 105 +#define LOG_DDM 1 +#define DDM_ON "$PSRF105,01*3E\r\n" +#define DDM_OFF "$PSRF105,00*3F\r\n" + +#define USE_WAAS 0 // useful in US, but slower fix +#define WAAS_ON "$PSRF151,01*3F\r\n" // the command for turning on WAAS +#define WAAS_OFF "$PSRF151,00*3E\r\n" // the command for turning off WAAS + +// read a Hex value and return the decimal equivalent +uint8_t parseHex(char c) { + if (c < '0') + return 0; + if (c <= '9') + return c - '0'; + if (c < 'A') + return 0; + if (c <= 'F') + return (c - 'A')+10; +} + +// blink out an error code +void error(uint8_t errno) { + while(1) { + for (i=0; i +#include + +// macros to use PSTR +#define putstring(str) SerialPrint_P(PSTR(str)) +#define putstring_nl(str) SerialPrintln_P(PSTR(str)) + +#define isdigit(x) ( x >= '0' && x <= '9') + +//extern uint16_t _end; + +SdCard card; +Fat16 f; + +#define led1Pin 4 // LED1 connected to digital pin 4 +#define led2Pin 3 // LED2 connected to digital pin 3 +#define powerpin 2 // GPS power control + +// set the RX_BUFFER_SIZE to 32! +#define BUFFSIZE 73 // we buffer one NMEA sentense at a time, 83 bytes is longer than the max length +char buffer[BUFFSIZE]; // this is the double buffer +char buffer2[12]; + +uint8_t bufferidx = 0; +uint32_t tmp; +#define LOG_RMC 1 // essential location data +#define RMC_ON "$PSRF103,4,0,1,1*21\r\n" // the command we send to turn RMC on (1 hz rate) +#define RMC_OFF "$PSRF103,4,0,0,1*20\r\n" // the command we send to turn RMC off + +#define LOG_GGA 0 // contains fix, hdop & vdop data +#define GGA_ON "$PSRF103,0,0,1,1*25\r\n" // the command we send to turn GGA on (1 hz rate) +#define GGA_OFF "$PSRF103,0,0,0,1*24\r\n" // the command we send to turn GGA off + +#define LOG_GSA 0 // satelite data +#define GSA_ON "$PSRF103,2,0,1,1*27\r\n" // the command we send to turn GSA on (1 hz rate) +#define GSA_OFF "$PSRF103,2,0,0,1*26\r\n" // the command we send to turn GSA off + +#define LOG_GSV 0 // detailed satellite data +#define GSV_ON "$PSRF103,3,0,1,1*26\r\n" // the command we send to turn GSV on (1 hz rate) +#define GSV_OFF "$PSRF103,3,0,0,1*27\r\n" // the command we send to turn GSV off + +#define LOG_GLL 0 // Loran-compatibility data +// this isnt output by default + +#define USE_WAAS 1 // useful in US, but slower fix +#define WAAS_ON "$PSRF151,1*3F\r\n" // the command for turning on WAAS +#define WAAS_OFF "$PSRF151,0*3E\r\n" // the command for turning off WAAS + +#define LOG_RMC_FIXONLY 1 // log only when we get RMC's with fix? +uint8_t fix = 0; // current fix data + +// read a Hex value and return the decimal equivalent +uint8_t parseHex(char c) { + if (c < '0') + return 0; + if (c <= '9') + return c - '0'; + if (c < 'A') + return 0; + if (c <= 'F') + return (c - 'A')+10; +} + +uint8_t i; + +// blink out an error code +void error(uint8_t errno) { + while(1) { + for (i=0; i 6) sensorCount = 6; + strncpy_P(buffer, PSTR("time,lat,long,speed,date,sens0,sens1,sens2,sens3,sens4,sens5"), 24 + 6*sensorCount); + Serial.println(buffer); + // clear write error + f.writeError = false; + f.println(buffer); + if (f.writeError || !f.sync()) { + putstring_nl("can't write header!"); + error(4); + } + + delay(1000); + + putstring("\r\n"); +#if USE_WAAS == 1 + putstring(WAAS_ON); // turn on WAAS +#else + putstring(WAAS_OFF); // turn on WAAS +#endif + +#if LOG_RMC == 1 + putstring(RMC_ON); // turn on RMC +#else + putstring(RMC_OFF); // turn off RMC +#endif + +#if LOG_GSV == 1 + putstring(GSV_ON); // turn on GSV +#else + putstring(GSV_OFF); // turn off GSV +#endif + +#if LOG_GSA == 1 + putstring(GSA_ON); // turn on GSA +#else + putstring(GSA_OFF); // turn off GSA +#endif + +#if LOG_GGA == 1 + putstring(GGA_ON); // turn on GGA +#else + putstring(GGA_OFF); // turn off GGA +#endif +} + +void loop() // run over and over again +{ + //Serial.println(Serial.available(), DEC); + char c; + uint8_t sum; + + // read one 'line' + if (Serial.available()) { + c = Serial.read(); + //Serial.print(c, BYTE); + if (bufferidx == 0) { + while (c != '$') + c = Serial.read(); // wait till we get a $ + } + buffer[bufferidx] = c; + + //Serial.print(c, BYTE); + if (c == '\n') { + //putstring_nl("EOL"); + //Serial.print(buffer); + buffer[bufferidx+1] = 0; // terminate it + + if (buffer[bufferidx-4] != '*') { + // no checksum? + Serial.print('*', BYTE); + bufferidx = 0; + return; + } + // get checksum + sum = parseHex(buffer[bufferidx-3]) * 16; + sum += parseHex(buffer[bufferidx-2]); + + // check checksum + for (i=1; i < (bufferidx-4); i++) { + sum ^= buffer[i]; + } + if (sum != 0) { + //putstring_nl("Cxsum mismatch"); + Serial.print('~', BYTE); + bufferidx = 0; + return; + } + // got good data! + + if (strstr(buffer, "GPRMC")) { + // find out if we got a fix + char* p = buffer; + p = strchr(p, ',')+1; + p = strchr(p, ',')+1; // skip to 3rd item + + if (p[0] == 'V') { + digitalWrite(led1Pin, LOW); + fix = 0; + } else { + digitalWrite(led1Pin, HIGH); + fix = 1; + } + } else { + // not GPRMC + bufferidx = 0; + return; + } +#if LOG_RMC_FIXONLY + if (!fix) { + Serial.print('_', BYTE); + bufferidx = 0; + return; + } +#endif + // rad. lets print it! + + Serial.print(buffer); + + // time to clean up the string + // find time + char* p = buffer; + p = strchr(p, ',')+1; + buffer[0] = p[0]; + buffer[1] = p[1]; + buffer[2] = ':'; + buffer[3] = p[2]; + buffer[4] = p[3]; + buffer[5] = ':'; + buffer[6] = p[4]; + buffer[7] = p[5]; + // we ignore milliseconds + buffer[8] = ','; + + p = strchr(buffer+8, ',')+1; + // skip past 'active' flag + p = strchr(p, ',')+1; + // find lat + p = strchr(p, ',')+1; + + buffer[9] = '+'; + buffer[10] = p[0]; + buffer[11] = p[1]; + buffer[12] = ' '; + strncpy(buffer+13, p+2, 7); + buffer[20] = ','; + + p = strchr(buffer+21, ',')+1; + if (p[0] == 'S') + buffer[9] = '-'; + + // find long + p = strchr(p, ',')+1; + buffer[21] = '+'; + buffer[22] = p[0]; + buffer[23] = p[1]; + buffer[24] = p[2]; + buffer[25] = ' '; + strncpy(buffer+26, p+3, 7); + buffer[33] = ','; + + p = strchr(buffer+34, ',')+1; + if (p[0] == 'W') + buffer[21] = '-'; + + // find speed + p = strchr(p, ',')+1; + tmp = 0; + if (p[0] != ',') { + // ok there is some sort of speed + while (p[0] != '.' && p[0] != ',') { + tmp *= 10; + tmp += p[0] - '0'; + p++; + } + tmp *= 10; + if (isdigit(p[1])) + tmp += p[1] - '0'; // tenths + tmp *= 10; + if (isdigit(p[2])) + tmp += p[2] - '0'; // hundredths + + // tmp is knots * 100 + // convert to mph (1.15 mph = 1 knot) + tmp *= 115; + // -OR- convert km/h + // tmp *= 185 + } + tmp /= 100; + + buffer[34] = (tmp / 10000) + '0'; + tmp %= 10000; + buffer[35] = (tmp / 1000) + '0'; + tmp %= 1000; + buffer[36] = (tmp / 100) + '0'; + tmp %= 100; + buffer[37] = '.'; + buffer[38] = (tmp / 10) + '0'; + tmp %= 10; + buffer[39] = tmp + '0'; + + buffer[40] = ','; + p = strchr(p, ',')+1; + // skip past bearing + p = strchr(p, ',')+1; + //mod for bug when speed,bearing are missing (bill greiman) + uint8_t date[6]; + for (uint8_t id = 0; id < 6; id++) date[id] = p[id]; + // get date into 2001-01-31 style + buffer[41] = '2'; + buffer[42] = '0'; + buffer[43] = date[4]; + buffer[44] = date[5]; + buffer[45] = '-'; + buffer[46] = date[2]; + buffer[47] = date[3]; + buffer[48] = '-'; + buffer[49] = date[0]; + buffer[50] = date[1]; + buffer[51] = 0; + digitalWrite(led2Pin, HIGH); + if(f.write((uint8_t*) buffer, 51) != 51) { + putstring_nl("can't write fix!"); + return; + } + Serial.print(buffer); + // clear write error + f.writeError = false; + // add sensor data + for (uint8_t ia = 0; ia < sensorCount; ia++) { + Serial.print(','); + f.print(','); + uint16_t data = analogRead(ia); + Serial.print(data); + f.print(data); + } + Serial.println(); + f.println(); + if (f.writeError || !f.sync()) { + putstring_nl("can't write data!"); + return; + } + digitalWrite(led2Pin, LOW); + bufferidx = 0; + return; + } + bufferidx++; + if (bufferidx == BUFFSIZE-1) { + Serial.print('!', BYTE); + bufferidx = 0; + } + } +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16append/fat16append.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16append/fat16append.pde new file mode 100644 index 0000000..745f3e1 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16append/fat16append.pde @@ -0,0 +1,67 @@ +/* + * Append Example + * + * This sketch shows how to use open for append and the Arduino Print class + * with Fat16. + */ +#include +#include // use functions to print strings from flash memory + +SdCard card; +Fat16 file; + +// store error strings in flash to save RAM +#define error(s) error_P(PSTR(s)) + +void error_P(const char* str) { + PgmPrint("error: "); + SerialPrintln_P(str); + if (card.errorCode) { + PgmPrint("SD error: "); + Serial.println(card.errorCode, HEX); + } + while(1); +} + +void setup(void) { + Serial.begin(9600); + Serial.println(); + PgmPrintln("Type any character to start"); + while (!Serial.available()); + + // initialize the SD card + if (!card.init()) error("card.init"); + + // initialize a FAT16 volume + if (!Fat16::init(&card)) error("Fat16::init"); + + char name[] = "APPEND.TXT"; + PgmPrint("Appending to: "); + Serial.println(name); + + // clear write error + file.writeError = false; + + for (uint8_t i = 0; i < 100; i++) { + // O_CREAT - create the file if it does not exist + // O_APPEND - seek to the end of the file prior to each write + // O_WRITE - open for write + if (!file.open(name, O_CREAT | O_APPEND | O_WRITE)) error("open"); + // print 100 lines to file + for (uint8_t j = 0; j < 100; j++) { + file.print("line "); + file.print(j, DEC); + file.print(" of pass "); + file.print(i, DEC); + file.print(" millis = "); + file.println(millis()); + if (file.writeError) error("write"); + } + if (!file.close()) error("close"); + if (i > 0 && i%25 == 0)Serial.println(); + Serial.print('.'); + } + Serial.println(); + Serial.println("Done"); +} +void loop(void){} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16bench/fat16bench.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16bench/fat16bench.pde new file mode 100644 index 0000000..fed4889 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16bench/fat16bench.pde @@ -0,0 +1,90 @@ +/* + * This sketch is a simple write/read benchmark. + */ +#include +#include + +#define FILE_SIZE_MB 5 +#define FILE_SIZE (1000000UL*FILE_SIZE_MB) +#define BUF_SIZE 100 + +uint8_t buf[BUF_SIZE]; + +SdCard card; +Fat16 file; + +// store error strings in flash to save RAM +#define error(s) error_P(PSTR(s)) + +void error_P(const char* str) { + PgmPrint("error: "); + SerialPrintln_P(str); + if (card.errorCode) { + PgmPrint("SD error: "); + Serial.println(card.errorCode, HEX); + } + while(1); +} + +void setup() { + Serial.begin(9600); + PgmPrintln("Type any character to start"); + while (!Serial.available()); + + PgmPrint("Free RAM: "); + Serial.println(FreeRam()); + + if (!card.init()) error("card.init failed!"); + if (!Fat16::init(&card)) error("Fat16::init failed!"); + + // open or create file - truncate existing file. + if (!file.open("BENCH.DAT", O_CREAT | O_TRUNC | O_RDWR)) { + error("open"); + } + + // fill buf with known data + for (uint16_t i = 0; i < (BUF_SIZE-2); i++) { + buf[i] = 'A' + (i % 26); + } + buf[BUF_SIZE-2] = '\r'; + buf[BUF_SIZE-1] = '\n'; + + PgmPrint("File size "); + Serial.print(FILE_SIZE_MB); + PgmPrintln(" MB"); + PgmPrintln("Starting write test. Please wait up to three minutes"); + + // do write test + uint32_t n =FILE_SIZE/sizeof(buf); + uint32_t t = millis(); + for (uint32_t i = 0; i < n; i++) { + if (file.write(buf, sizeof(buf)) != sizeof(buf)) { + error("write"); + } + } + t = millis() - t; + file.sync(); + double r = (double)file.fileSize()/t; + PgmPrint("Write "); + Serial.print(r); + PgmPrintln(" KB/sec"); + Serial.println(); + PgmPrintln("Starting read test. Please wait up to a minute"); + + // do read test + file.rewind(); + t = millis(); + for (uint32_t i = 0; i < n; i++) { + if (file.read(buf, sizeof(buf)) != sizeof(buf)) { + error("read"); + } + } + t = millis() - t; + r = (double)file.fileSize()/t; + PgmPrint("Read "); + Serial.print(r); + PgmPrintln(" KB/sec"); + PgmPrintln("Done"); +} + +void loop() { } diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16copy/fat16copy.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16copy/fat16copy.pde new file mode 100644 index 0000000..2eaf7f9 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16copy/fat16copy.pde @@ -0,0 +1,74 @@ +/* + * Copy Example - only runs on chips with 2K or more RAM + * + * This sketch copies the file APPEND.TXT, created by the + * fat16append.pde example, to the file ACOPY.TXT. + */ +#include +#include // use functions to print strings from flash memory + +// large buffer to test for bugs. 512 bytes runs much faster. +char buf[600]; + +SdCard card; +Fat16 from; // read file +Fat16 copy; // write file + +// store error strings in flash to save RAM +#define error(s) error_P(PSTR(s)) + +void error_P(const char* str) { + PgmPrint("error: "); + SerialPrintln_P(str); + if (card.errorCode) { + PgmPrint("SD error: "); + Serial.println(card.errorCode, HEX); + } + while(1); +} + +void setup(void) { + Serial.begin(9600); + Serial.println(); + PgmPrintln("Type any character to start"); + while (!Serial.available()); + + PgmPrint("FreeRam: "); + Serial.println(FreeRam()); + + // initialize the SD card + if (!card.init()) error("card.init"); + + // initialize a FAT16 volume + if (!Fat16::init(&card)) error("Fat16::init"); + + strcpy_P(buf, PSTR("APPEND.TXT")); + // open for read + if (!from.open(buf, O_READ)) { + PgmPrint("Can't open "); + Serial.println(buf); + PgmPrintln("Run the append example to create the file."); + error("from.open"); + } + strcpy_P(buf, PSTR("ACOPY.TXT")); + // create if needed, truncate to zero length, open for write + if (!copy.open(buf, O_CREAT | O_TRUNC | O_WRITE)) { + error("copy.open"); + } + // count for printing periods + uint16_t p = 0; + int16_t n; + while ((n = from.read(buf, sizeof(buf))) > 0) { + if (copy.write(buf, n) != n) error("write"); + // print progress periods + if (!(p++ % 25)) Serial.print('.'); + if (!(p % 500)) Serial.println(); + } + Serial.println(); + if (n != 0) error ("read"); + // force write of directory entry and last data + if (!copy.close()) error("close copy"); + PgmPrintln("Copy done."); +} + +void loop(void) {} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16info/fat16info.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16info/fat16info.pde new file mode 100644 index 0000000..bcff4f3 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16info/fat16info.pde @@ -0,0 +1,234 @@ +/* + * This sketch attempts to initialize a SD card and analyze its format. + */ +#include +#include // use functions to print strings from flash memory + +SdCard card; +Fat16 file; + +void sdError(void) { + if (card.errorCode) { + PgmPrintln("SD error"); + PgmPrint("errorCode: "); + Serial.println(card.errorCode, HEX); + PgmPrint("errorData: "); + Serial.println(card.errorData, HEX); + } + return; +} + +uint8_t cidDmp(void) { + cid_t cid; + if (!card.readCID(&cid)) { + PgmPrintln("readCID failed"); + sdError(); + while(1); + } + PgmPrint("\nManufacturer ID: "); + Serial.println(cid.mid, HEX); + PgmPrint("OEM ID: "); + Serial.print(cid.oid[0]); + Serial.println(cid.oid[1]); + PgmPrint("Product: "); + for (uint8_t i = 0; i < 5; i++)Serial.print(cid.pnm[i]); + PgmPrint("\nVersion: "); + Serial.print(cid.prv_n, DEC); + Serial.print('.'); + Serial.println(cid.prv_m, DEC); + PgmPrint("Serial number: "); + Serial.println(cid.psn); + PgmPrint("Manufacturing date: "); + Serial.print(cid.mdt_month); + Serial.print('/'); + Serial.println(2000 + cid.mdt_year_low + (cid.mdt_year_high <<4)); + Serial.println(); + return 1; +} + +/* + * print partition info + */ +uint8_t partitionInfo(void) { + mbr_t* mbr = (mbr_t*)Fat16::dbgCacheBlock(0); + if (mbr == 0) { + PgmPrintln("partitionInfo: cacheBlock(0) failed"); + return 0; + } + uint8_t good = 0; + for (uint8_t i = 0; i < 4; i++) { + if ((mbr->part[i].boot & 0X7F) != 0 || + (mbr->part[i].firstSector == 0 && mbr->part[i].totalSectors != 0)) { + // not a valid partition table + return 0; + } + if (mbr->part[i].firstSector != 0 && mbr->part[i].totalSectors != 0) { + //might be ok + good = 1; + } + } + if (!good) return 0; + PgmPrintln("Partition Table:"); + PgmPrintln("part,boot,type,start,size"); + for (uint8_t i = 0; i < 4; i++) { + Serial.print(i+1); + Serial.print(','); + Serial.print(mbr->part[i].boot, HEX); + Serial.print(','); + Serial.print(mbr->part[i].type, HEX); + Serial.print(','); + Serial.print(mbr->part[i].firstSector); + Serial.print(','); + Serial.println(mbr->part[i].totalSectors); + } + Serial.println(); + return 1; +} +/* + * print info for FAT volume + */ +uint8_t volumeInfo(uint8_t part) { + uint8_t volumeType = 0; + if (part > 4) { + PgmPrintln("volumeInfo: invalid partition number"); + return 0; + } + mbr_t* mbr = (mbr_t*)Fat16::dbgCacheBlock(0); + if (mbr == 0) { + PgmPrintln("volumeInfo: cacheBlock(0) failed"); + return 0; + } + bpb_t* bpb = &(((fbs_t*)mbr)->bpb); + if (part != 0) { + if ((mbr->part[part-1].boot & 0X7F) !=0 || + mbr->part[part-1].totalSectors < 100 || + mbr->part[part-1].firstSector == 0) { + //not a valid partition + return 0; + } + fbs_t* fbs = (fbs_t*)Fat16::dbgCacheBlock(mbr->part[part-1].firstSector); + if (fbs == 0) { + PgmPrintln("volumeInfo cacheBlock(fat boot sector) failed"); + return 0; + } + if (fbs->bootSectorSig0 != 0X55 || fbs->bootSectorSig1 != 0XAA) { + PgmPrintln("Bad FAT boot sector signature for partition: "); + Serial.println(part, DEC); + return 0; + } + bpb = &fbs->bpb; + } + if (bpb->bytesPerSector != 512 || + bpb->fatCount == 0 || + bpb->reservedSectorCount == 0 || + bpb->sectorsPerCluster == 0 || + (bpb->sectorsPerCluster & (bpb->sectorsPerCluster - 1)) != 0) { + // not valid FAT volume + return 0; + } + uint32_t totalBlocks = bpb->totalSectors16 ? bpb->totalSectors16 : bpb->totalSectors32; + uint32_t fatSize = bpb->sectorsPerFat16; + if (fatSize == 0) { + // first entry of FAT32 structure is FatSize32 + // don't ask why this works + fatSize = *(&bpb->totalSectors32 + 1); + } + uint16_t rootDirSectors = (32*bpb->rootDirEntryCount + 511)/512; + uint32_t firstDataSector = bpb->reservedSectorCount + + bpb->fatCount*fatSize + rootDirSectors; + uint32_t dataBlockCount = totalBlocks - firstDataSector; + uint32_t clusterCount = dataBlockCount/bpb->sectorsPerCluster; + if (part) { + PgmPrint("FAT Volume info for partition: "); + Serial.println(part, DEC); + } else { + PgmPrintln("FAT Volume is super floppy format"); + } + if (clusterCount < 4085) { + volumeType = 12; + } else if (clusterCount < 65525) { + volumeType = 16; + } else { + volumeType = 32; + } + PgmPrint("Volume is FAT"); + Serial.println(volumeType, DEC); + PgmPrint("clusterSize: "); + Serial.println(bpb->sectorsPerCluster, DEC); + PgmPrint("clusterCount: "); + Serial.println(clusterCount); + PgmPrint("fatCount: "); + Serial.println(bpb->fatCount, DEC); + PgmPrint("fatSize: "); + Serial.println(fatSize); + PgmPrint("totalBlocks: "); + Serial.println(totalBlocks); + Serial.println(); + return volumeType; +} +void setup() { + Serial.begin(9600); + delay(500); + Serial.println(); + PgmPrint("FreeRam: "); + Serial.println(FreeRam(), DEC); +} + +void loop() { + PgmPrintln("\ntype any character to start"); + while (!Serial.available()); + Serial.flush(); + int8_t part = -1; + uint32_t t0 = millis(); + if (!card.init()) { + PgmPrintln("card.init failed"); + sdError(); + return; + } + uint32_t d = millis()- t0; + PgmPrint("\ninit time: ");Serial.println(d); + cidDmp(); + uint32_t size = card.cardSize(); + PgmPrint("Card Size(blocks): "); + Serial.println(size); + if (size < 1000) { + PgmPrint("Quitting, bad size"); + return; + } + Serial.println(); + Fat16::dbgSetDev(&card); + if (partitionInfo()) { + for (uint8_t i = 1; i < 5; i++) { + if (volumeInfo(i) == 16) part = i; + } + } else { + PgmPrintln("Card is not MBR trying super floppy"); + if (volumeInfo(0) == 16) part = 0; + } + if (part >= 0) { + if (!Fat16::init(&card, part)) { + PgmPrintln("Can't init volume"); + return; + } + uint16_t index = 0; + dir_t d; + PgmPrintln("Root Directory:"); + PgmPrintln("name ext att size"); + uint8_t nd = 0; + //list up to 20 files + while ((Fat16::readDir(&d, &index)) && nd++ < 20) { + for (uint8_t i = 0; i < 11; i++) { + if (i == 8)Serial.print(' '); + Serial.print((char)d.name[i]); + } + Serial.print(' '); + Serial.print(d.attributes, HEX); + Serial.print(' '); + Serial.println(d.fileSize); + index++; + } + PgmPrintln("\nDone"); + } else { + PgmPrintln("FAT16 volume not found"); + } +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16ls/fat16ls.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16ls/fat16ls.pde new file mode 100644 index 0000000..96f0159 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16ls/fat16ls.pde @@ -0,0 +1,41 @@ +/* + * List files in root directory. + */ +#include +#include + +SdCard card; + +// store error strings in flash to save RAM +#define error(s) error_P(PSTR(s)) + +void error_P(const char* str) { + PgmPrint("error: "); + SerialPrintln_P(str); + if (card.errorCode) { + PgmPrint("SD error: "); + Serial.println(card.errorCode, HEX); + } + while(1); +} + +void setup() { + Serial.begin(9600); + PgmPrintln("Type any character to start"); + while (!Serial.available()); + + PgmPrint("Free RAM: "); + Serial.println(FreeRam()); + + if (!card.init()) error("card.init failed!"); + + if (!Fat16::init(&card)) error("Fat16::init failed!"); + + Serial.println(); + + PgmPrintln("Name Modify Date/Time Size"); + + Fat16::ls(LS_DATE | LS_SIZE); +} + +void loop() { } diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16print/fat16print.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16print/fat16print.pde new file mode 100644 index 0000000..f314b9f --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16print/fat16print.pde @@ -0,0 +1,65 @@ +/* + * Print Example + * + * This sketch shows how to use the Arduino Print class with Fat16. + */ +#include +#include // use functions to print strings from flash memory + +SdCard card; +Fat16 file; + +// store error strings in flash to save RAM +#define error(s) error_P(PSTR(s)) + +void error_P(const char* str) { + PgmPrint("error: "); + SerialPrintln_P(str); + if (card.errorCode) { + PgmPrint("SD error: "); + Serial.println(card.errorCode, HEX); + } + while(1); +} + +void setup(void) { + Serial.begin(9600); + Serial.println(); + PgmPrintln("Type any character to start"); + while (!Serial.available()); + + // initialize the SD card + if (!card.init()) error("card.init"); + + // initialize a FAT16 volume + if (!Fat16::init(&card)) error("Fat16::init"); + + // create a new file + char name[] = "PRINT00.TXT"; + for (uint8_t i = 0; i < 100; i++) { + name[5] = i/10 + '0'; + name[6] = i%10 + '0'; + // O_CREAT - create the file if it does not exist + // O_EXCL - fail if the file exists + // O_WRITE - open for write + if (file.open(name, O_CREAT | O_EXCL | O_WRITE)) break; + } + if (!file.isOpen()) error ("create"); + PgmPrint("Printing to: "); + Serial.println(name); + + // clear write error + file.writeError = false; + + // print 100 line to file + for (uint8_t i = 0; i < 100; i++) { + file.print("line "); + file.print(i, DEC); + file.print(" millis = "); + file.println(millis()); + } + // force write of all data to the SD card + if (file.writeError || !file.sync()) error ("print or sync"); + PgmPrint("Done"); +} +void loop(void){} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16read/fat16read.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16read/fat16read.pde new file mode 100644 index 0000000..ce3462c --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16read/fat16read.pde @@ -0,0 +1,61 @@ +/* + * This sketch reads and prints the file + * PRINT00.TXT created by fat16print.pde or + * WRITE00.TXT created by fat16write.pde + */ +#include +#include // use functions to print strings from flash memory + +SdCard card; +Fat16 file; + +// store error strings in flash to save RAM +#define error(s) error_P(PSTR(s)) + +void error_P(const char* str) { + PgmPrint("error: "); + SerialPrintln_P(str); + if (card.errorCode) { + PgmPrint("SD error: "); + Serial.println(card.errorCode, HEX); + } + while(1); +} + +void setup(void) { + Serial.begin(9600); + Serial.println(); + PgmPrintln("type any character to start"); + while (!Serial.available()); + Serial.println(); + + // initialize the SD card + if (!card.init()) error("card.init"); + + // initialize a FAT16 volume + if (!Fat16::init(&card)) error("Fat16::init"); + + // open a file + if (file.open("PRINT00.TXT", O_READ)) { + PgmPrintln("Opened PRINT00.TXT"); + } else if (file.open("WRITE00.TXT", O_READ)) { + PgmPrintln("Opened WRITE00.TXT"); + } else{ + error("file.open"); + } + Serial.println(); + + // copy file to serial port + int16_t n; + uint8_t buf[7];// nothing special about 7, just a lucky number. + while ((n = file.read(buf, sizeof(buf))) > 0) { + for (uint8_t i = 0; i < n; i++) Serial.print(buf[i]); + } + /* easier way + int16_t c; + while ((c = file.read()) > 0) Serial.print((char)c); + */ + PgmPrintln("\nDone"); +} + +void loop(void) {} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16remove/fat16remove.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16remove/fat16remove.pde new file mode 100644 index 0000000..f1a1345 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16remove/fat16remove.pde @@ -0,0 +1,50 @@ +/* + * Remove Example + * + * This sketch shows how to use remove() to delete + * the file created by the fat16append.pde example. + */ +#include "Fat16.h" +#include // use functions to print strings from flash memory + +SdCard card; +Fat16 file; + +// store error strings in flash to save RAM +#define error(s) error_P(PSTR(s)) + +void error_P(const char* str) { + PgmPrint("error: "); + SerialPrintln_P(str); + if (card.errorCode) { + PgmPrint("SD error: "); + Serial.println(card.errorCode, HEX); + } + while(1); +} + +void setup(void) { + Serial.begin(9600); + Serial.println(); + PgmPrintln("Type any character to start"); + while (!Serial.available()); + + // initialize the SD card + if (!card.init()) error("card.init"); + + // initialize a FAT16 volume + if (!Fat16::init(&card)) error("Fat16::init"); + + char name[] = "APPEND.TXT"; + if (!file.open(name, O_WRITE)) { + PgmPrint("Can't open "); + Serial.println(name); + PgmPrintln("Run the append example to create the file."); + error("open"); + } + if (!file.remove()) error("file.remove"); + Serial.print(name); + PgmPrintln(" deleted."); +} + +void loop(void) {} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16rewrite/fat16rewrite.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16rewrite/fat16rewrite.pde new file mode 100644 index 0000000..7bd7a6f --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16rewrite/fat16rewrite.pde @@ -0,0 +1,64 @@ +/* + * Rewrite Example + * + * This sketch shows how to rewrite part of a line in the middle + * of the file created by the fat16append.pde example. + * + * Check around line 30 of pass 50 of APPEND.TXT after running this sketch. + */ +#include +#include // use functions to print strings from flash memory + +SdCard card; +Fat16 file; + +// store error strings in flash to save RAM +#define error(s) error_P(PSTR(s)) + +void error_P(const char* str) { + PgmPrint("error: "); + SerialPrintln_P(str); + if (card.errorCode) { + PgmPrint("SD error: "); + Serial.println(card.errorCode, HEX); + } + while(1); +} + +void setup(void) { + Serial.begin(9600); + Serial.println(); + PgmPrintln("Type any character to start"); + while (!Serial.available()); + + // initialize the SD card + if (!card.init()) error("card.init"); + + // initialize a FAT16 volume + if (!Fat16::init(&card)) error("Fat16::init"); + + char name[] = "APPEND.TXT"; + // open for read and write + if (!file.open(name, O_RDWR)) { + PgmPrint("Can't open "); + Serial.println(name); + PgmPrintln("Run the append example to create the file."); + error("file.open"); + } + // seek to middle of file + if (!file.seekSet(file.fileSize()/2)) error("file.seekSet"); + // find end of line + int16_t c; + while ((c = file.read()) > 0 && c != '\n'); + if (c < 0) error("file.read"); + // clear write error flag + file.writeError = false; + // rewrite the begining of the line at the current position + file.write("**rewrite**"); + if (file.writeError) error("file.write"); + if (!file.close()) error("file.close"); + Serial.print(name); + PgmPrintln(" rewrite done."); +} + +void loop(void) {} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16tail/fat16tail.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16tail/fat16tail.pde new file mode 100644 index 0000000..32d1577 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16tail/fat16tail.pde @@ -0,0 +1,85 @@ +/* + * This sketch reads and prints the tail of all files + * created by fat16append.pde, fat16print.pde and fat16write.pde. + */ +#include +#include // use functions to print strings from flash memory + +SdCard card; +Fat16 file; + +// store error strings in flash to save RAM +#define error(s) error_P(PSTR(s)) + +void error_P(const char* str) { + PgmPrint("error: "); + SerialPrintln_P(str); + if (card.errorCode) { + PgmPrint("SD error: "); + Serial.println(card.errorCode, HEX); + } + while(1); +} + +void setup(void) { + Serial.begin(9600); + Serial.println(); + PgmPrintln("type any character to start"); + while (!Serial.available()); + Serial.println(); + + // initialize the SD card + if (!card.init()) error("card.init"); + + // initialize a FAT16 volume + if (!Fat16::init(&card)) error("Fat16::init"); +} +uint16_t index = 0; +/* + * Print tail of Fat16 example files + */ +void loop(void) { + dir_t dir; + // read next directory entry + if (!Fat16::readDir(&dir, &index)) { + PgmPrintln("End of Directory"); + // halt + while(1); + } + // remember found file and advance index for next dir + uint16_t found = index++; + + // check for file name "APPEND*.TXT", "PRINT*.TXT", or "WRITE*.TXT" + // first 8 bytes are blank filled name + // last three bytes are blank filled extension + if ((strncmp((char *)dir.name, "APPEND", 6) && + strncmp((char *)dir.name, "WRITE", 5) && + strncmp((char *)dir.name, "PRINT", 5)) || + strncmp((char *)&dir.name[8], "TXT", 3)) { + return; + } + // open file by index - easier to use than open by name. + if (!file.open(found, O_READ)) error("file.open"); + + // print file name message + PgmPrint("Tail of: "); + for(uint8_t i = 0; i < 11; i++){ + if(dir.name[i] == ' ') continue; + if (i == 8) Serial.print('.'); + Serial.print(dir.name[i]); + } + Serial.println(); + + // position to tail of file + if (file.fileSize() > 100) { + if (!file.seekSet(file.fileSize() - 100)) error("file.seekSet"); + } + int16_t c; + // find end of line + while ((c = file.read()) > 0 && c != '\n'); + + // print rest of file + while ((c = file.read()) > 0) Serial.print((char)c); + file.close(); + Serial.println(); +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16timestamp/fat16timestamp.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16timestamp/fat16timestamp.pde new file mode 100644 index 0000000..f988b23 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16timestamp/fat16timestamp.pde @@ -0,0 +1,174 @@ +/* + * This sketch tests the dateTimeCallback() function + * and the timestamp() function. + */ +#include +#include // use PgmPrint +/* + * date/time values for debug + * normally supplied by a real-time clock or GPS + */ +// date 2009-10-01 1-Oct-09 +uint16_t year = 2009; +uint8_t month = 10; +uint8_t day = 1; + +// time 20:30:40 +uint8_t hour = 20; +uint8_t minute = 30; +uint8_t second = 40; +/* + * User provided date time callback function. + * See Fat16::dateTimeCallback() for usage. + */ +void dateTime(uint16_t* date, uint16_t* time) { + // User gets date and time from GPS or real-time + // clock in real callback function + + // return date using FAT_DATE macro to format fields + *date = FAT_DATE(year, month, day); + + // return time using FAT_TIME macro to format fields + *time = FAT_TIME(hour, minute, second); +} + +SdCard card; +Fat16 file; + +// store error strings in flash to save RAM +#define error(s) error_P(PSTR(s)) + +void error_P(const char* str) { + PgmPrint("error: "); + SerialPrintln_P(str); + if (card.errorCode) { + PgmPrint("SD error: "); + Serial.println(card.errorCode, HEX); + } + while(1); +} +/* + * Function to print all timestamps. + */ +void printTimestamps(Fat16& f) { + dir_t d; + if (!f.dirEntry(&d)) error("dirEntry"); + + PgmPrint("Creation: "); + f.printFatDate(d.creationDate); + Serial.print(' '); + f.printFatTime(d.creationTime); + Serial.println(); + + PgmPrint("Modify: "); + f.printFatDate(d.lastWriteDate); + Serial.print(' '); + f.printFatTime(d.lastWriteTime); + Serial.println(); + + PgmPrint("Access: "); + f.printFatDate(d.lastAccessDate); + Serial.println(); +} + +void setup(void) { + Serial.begin(9600); + Serial.println(); + PgmPrintln("Type any character to start"); + while (!Serial.available()); + + // initialize the SD card + if (!card.init()) error("card.init"); + + // initialize a FAT volume + if (!Fat16::init(&card)) error("volume.init"); + + // remove files if they exist + Fat16::remove("CALLBACK.TXT"); + Fat16::remove("DEFAULT.TXT"); + Fat16::remove("STAMP.TXT"); + + // create a new file with default timestamps + if (!file.open("DEFAULT.TXT", O_CREAT | O_WRITE)) { + error("open DEFAULT.TXT"); + } + Serial.println(); + PgmPrintln("Open with default times"); + printTimestamps(file); + + // close file + file.close(); + /* + * Test the date time callback function. + * + * dateTimeCallback() sets the function + * that is called when a file is created + * or when a file's directory entry is + * modified by sync(). + * + * The callback can be disabled by the call + * SdFile::dateTimeCallbackCancel() + */ + // set date time callback function + Fat16::dateTimeCallback(dateTime); + + // create a new file with callback timestamps + if (!file.open("CALLBACK.TXT", O_CREAT | O_WRITE)) { + error("open CALLBACK.TXT"); + } + Serial.println(); + PgmPrintln("Open with callback times"); + printTimestamps(file); + + // change call back date + day += 1; + + // must add two to see change since FAT second field is 5-bits + second += 2; + + // modify file by writing a byte + file.write('t'); + + // force dir update + file.sync(); + + Serial.println(); + PgmPrintln("Times after write"); + printTimestamps(file); + + // close file + file.close(); + /* + * Test timestamp() function + * + * Cancel callback so sync will not + * change access/modify timestamp + */ + Fat16::dateTimeCallbackCancel(); + + // create a new file with default timestamps + if (!file.open("STAMP.TXT", O_CREAT | O_WRITE)) { + error("open STAMP.TXT"); + } + // set creation date time + if (!file.timestamp(T_CREATE, 2009, 11, 10, 1, 2, 3)) { + error("create time"); + } + // set write/modification date time + if (!file.timestamp(T_WRITE, 2009, 11, 11, 4, 5, 6)) { + error("write time"); + } + // set access date + if (!file.timestamp(T_ACCESS, 2009, 11, 12, 7, 8, 9)) { + error("access time"); + } + Serial.println(); + PgmPrintln("Times after timestamp() calls"); + printTimestamps(file); + + file.close(); + Serial.println(); + PgmPrintln("Done"); +} + +void loop(void){} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16truncate/fat16truncate.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16truncate/fat16truncate.pde new file mode 100644 index 0000000..0a2b355 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16truncate/fat16truncate.pde @@ -0,0 +1,58 @@ +/* + * Truncate Example + * + * This sketch shows how to use truncate() to remove the last + * half of the file created by the fat16append.pde example. + */ +#include +#include // use functions to print strings from flash memory + +SdCard card; +Fat16 file; + +// store error strings in flash to save RAM +#define error(s) error_P(PSTR(s)) + +void error_P(const char* str) { + PgmPrint("error: "); + SerialPrintln_P(str); + if (card.errorCode) { + PgmPrint("SD error: "); + Serial.println(card.errorCode, HEX); + } + while(1); +} + +void setup(void) { + Serial.begin(9600); + Serial.println(); + PgmPrintln("Type any character to start"); + while (!Serial.available()); + + // initialize the SD card + if (!card.init()) error("card.init"); + + // initialize a FAT16 volume + if (!Fat16::init(&card)) error("Fat16::init"); + + char name[] = "APPEND.TXT"; + // open for read and write + if (!file.open(name, O_RDWR)) { + PgmPrint("Can't open "); + Serial.println(name); + PgmPrintln("Run the append example to create the file."); + error("file.open"); + } + // seek to middle of file + if (!file.seekSet(file.fileSize()/2)) error("file.seekSet"); + // find end of line + int16_t c; + while ((c = file.read()) > 0 && c != '\n'); + if (c < 0) error("file.read"); + // trucate at current position + if (!file.truncate(file.curPosition())) error("file.truncate"); + Serial.print(name); + PgmPrintln(" truncated."); +} + +void loop(void) {} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16write/fat16write.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16write/fat16write.pde new file mode 100644 index 0000000..8994bbd --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/Fat16/examples/fat16write/fat16write.pde @@ -0,0 +1,80 @@ +/* + * Write Example + * + * This sketch creates a new file and writes 100 lines to the file. + * No error checks on write in this example. + */ + +#include +#include // use functions to print strings from flash memory + +SdCard card; +Fat16 file; + +// store error strings in flash to save RAM +#define error(s) error_P(PSTR(s)) + +void error_P(const char* str) { + PgmPrint("error: "); + SerialPrintln_P(str); + if (card.errorCode) { + PgmPrint("SD error: "); + Serial.println(card.errorCode, HEX); + } + while(1); +} + +/* + * Write an unsigned number to file + */ +void writeNumber(uint32_t n) { + uint8_t buf[10]; + uint8_t i = 0; + do { + i++; + buf[sizeof(buf) - i] = n%10 + '0'; + n /= 10; + } while (n); + file.write(&buf[sizeof(buf) - i], i); // write the part of buf with the number +} + +void setup(void) { + Serial.begin(9600); + Serial.println(); + PgmPrintln("Type any character to start"); + while (!Serial.available()); + + // initialize the SD card + if (!card.init()) error("card.init"); + + // initialize a FAT16 volume + if (!Fat16::init(&card)) error("Fat16::init"); + + // create a new file + char name[] = "WRITE00.TXT"; + for (uint8_t i = 0; i < 100; i++) { + name[5] = i/10 + '0'; + name[6] = i%10 + '0'; + // O_CREAT - create the file if it does not exist + // O_EXCL - fail if the file exists + // O_WRITE - open for write + if (file.open(name, O_CREAT | O_EXCL | O_WRITE)) break; + } + if (!file.isOpen()) error ("file.open"); + PgmPrint("Writing to: "); + Serial.println(name); + + // write 100 line to file + for (uint8_t i = 0; i < 100; i++) { + file.write("line "); // write string from RAM + writeNumber(i); + file.write_P(PSTR(" millis = ")); // write string from flash + writeNumber(millis()); + file.write("\r\n"); // file.println() would work also + } + // close file and force write of all data to the SD card + file.close(); + PgmPrintln("Done"); +} + +void loop(void) {} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/HOWTO Using the chibiArduino Wireless Protocol Stack.pdf b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/HOWTO Using the chibiArduino Wireless Protocol Stack.pdf new file mode 100644 index 0000000..b224102 Binary files /dev/null and b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/HOWTO Using the chibiArduino Wireless Protocol Stack.pdf differ diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/chibi.cpp b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/chibi.cpp new file mode 100644 index 0000000..1a79614 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/chibi.cpp @@ -0,0 +1,279 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +/*! + \file + \ingroup + + +*/ +/**************************************************************************/ +#include "chibi.h" + +// Including the actual "c" files rather than the headers. The Arduino lib only +// recognizes one source file in the directory so all the source files need to look like +// they're in the one file. +#include "src/chb.c" +#include "src/chb_buf.c" +#include "src/chb_drvr.c" +#include "src/chb_spi.c" +#include "src/chb_eeprom.c" +#include "src/chb_cmd.c" + +#if (CHB_RX_POLLING_MODE) + #include "src/chb_rx_poll.c" +#else + #include "src/chb_rx_int.c" +#endif + +// used to store info about received data +static chb_rx_data_t rx_data; + +/**************************************************************************/ +/*! + Init the chibi stack +*/ +/**************************************************************************/ +void chibiInit() +{ + chb_init(); +} + +/**************************************************************************/ +/*! + Set the short address of the wireless node. This is the 16-bit "nickname" + of your node and what will be used to identify it. +*/ +/**************************************************************************/ +void chibiSetShortAddr(uint16_t addr) +{ + chb_set_short_addr(addr); +} + +/**************************************************************************/ +/*! + Retrieve the short address of the node. +*/ +/**************************************************************************/ +uint16_t chibiGetShortAddr() +{ + return chb_get_short_addr(); +} + +/**************************************************************************/ +/*! + Sets the 64-bit IEEE address of the node. +*/ +/**************************************************************************/ +void chibiSetIEEEAddr(uint8_t *ieee_addr) +{ + chb_set_ieee_addr((uint8_t *)ieee_addr); +} + +/**************************************************************************/ +/*! + Retrieves the 64-bit IEEE address of the node. +*/ +/**************************************************************************/ +void chibiGetIEEEAddr(uint8_t *ieee_addr) +{ + chb_get_ieee_addr((uint8_t *)ieee_addr); +} + +/**************************************************************************/ +/*! + +*/ +/**************************************************************************/ +uint8_t chibiRegRead(uint8_t addr) +{ + return chb_reg_read(addr); +} + +/**************************************************************************/ +/*! + +*/ +/**************************************************************************/ +void chibiRegWrite(uint8_t addr, uint8_t val) +{ + chb_reg_write(addr, val); +} + +/**************************************************************************/ +/*! + Transmit data to another node wirelessly using Chibi stack. + Usage: send +*/ +/**************************************************************************/ +uint8_t chibiTx(uint16_t addr, uint8_t *data, uint8_t len) +{ + return chb_write(addr, (uint8_t *)data, len); +} + +/**************************************************************************/ +/*! + This function should be polled in the "loop" portion of the code. It will + return false if no data has been received or true if data has arrived. +*/ +/**************************************************************************/ +uint8_t chibiDataRcvd() +{ + pcb_t *pcb = chb_get_pcb(); + +#if (CHB_RX_POLLING_MODE) + // need to poll for received data if we're not retrieving the data + // in the ISR + chb_rcv_poll(); +#endif + + return pcb->data_rcv; +} + +/**************************************************************************/ +/*! + Retrieves the data from the frame. A char array needs to be passed into + the function and the data will be copied into it. The character array + should be at least the size of a maximum sized frame for safety. It can + be smaller to save RAM but this should be done carefully to avoid buffer + overflows. +*/ +/**************************************************************************/ +uint8_t chibiGetData(uint8_t *data) +{ + // point the data buffer to the buffer that was passed in from arduino ide + rx_data.data = (U8 *)data; + + // load the data into the buffer and get the length + rx_data.len = chb_read(&rx_data); + return rx_data.len; +} + +/**************************************************************************/ +/*! + Returns the signal strength recorded from the last received frame. +*/ +/**************************************************************************/ +uint8_t chibiGetRSSI() +{ + pcb_t *pcb = chb_get_pcb(); + return pcb->ed; +} + +/**************************************************************************/ +/*! + Get the source address of the most recently received frame +*/ +/**************************************************************************/ +uint16_t chibiGetSrcAddr() +{ + return rx_data.src_addr; +} + +/**************************************************************************/ +/*! + Puts the radio to sleep to save power. It cuts approximately 15 mA of + current from the system. +*/ +/**************************************************************************/ +void chibiSleepRadio(uint8_t enb) +{ + chb_sleep(enb); +} + +/**************************************************************************/ +/*! + Sets the channel for the radio. Available channels are channels 11 to 26. +*/ +/**************************************************************************/ +uint8_t chibiSetChannel(uint8_t channel) +{ + return chb_set_channel(channel); +} + +/**************************************************************************/ +/*! + Gets the current channel for the radio. +*/ +/**************************************************************************/ +uint8_t chibiGetChannel() +{ + return chb_get_channel(); +} + +/**************************************************************************/ +/*! + Initialize the command line interface +*/ +/**************************************************************************/ +void chibiCmdInit(uint32_t speed) +{ + chb_cmd_init(speed); +} + +/**************************************************************************/ +/*! + Poll the command line interface. This should be in the loop portion of + the code and will check for any typed characters. If any typed characters + are found, they will be parsed and checked for a match with commands + in the command table. +*/ +/**************************************************************************/ +void chibiCmdPoll() +{ + chb_cmd_poll(); +} + +/**************************************************************************/ +/*! + Add a command to the command table in the command line interface. +*/ +/**************************************************************************/ +void chibiCmdAdd(char *name, void (*func)(int argc, char **argv)) +{ + chb_cmd_add(name, func); + +} + +/**************************************************************************/ +/*! + This function performs converts an ASCII number string into the actual number. + The first argument is the string to be converted, the second argument is + the base that it should use for the conversion (ie: decimal = 10, hexadecimal = 16). +*/ +/**************************************************************************/ +uint32_t chibiCmdStr2Num(char *str, uint8_t base) +{ + return chb_cmd_str2num(str, base); +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/chibi.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/chibi.h new file mode 100644 index 0000000..d0286ec --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/chibi.h @@ -0,0 +1,68 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +/*! + \file + \ingroup + + +*/ +/**************************************************************************/ +#ifndef CHIBI_H +#define CHIBI_H + +#include +#include "chibiUsrCfg.h" + +#define BROADCAST_ADDR 0xFFFF + +void chibiInit(); +void chibiSetShortAddr(uint16_t addr); +uint16_t chibiGetShortAddr(); +void chibiSetIEEEAddr(uint8_t *ieee_addr); +void chibiGetIEEEAddr(uint8_t *ieee_addr); +uint8_t chibiRegRead(uint8_t addr); +void chibiRegWrite(uint8_t addr, uint8_t val); +uint8_t chibiTx(uint16_t addr, uint8_t *data, uint8_t len); +uint8_t chibiDataRcvd(); +uint8_t chibiGetData(uint8_t *data); +uint8_t chibiGetRSSI(); +uint16_t chibiGetSrcAddr(); +uint8_t chibiSetChannel(uint8_t channel); +void chibiSleepRadio(uint8_t enb); +void chibiCmdInit(uint32_t speed); +void chibiCmdPoll(); +void chibiCmdAdd(char *name, void (*func)(int argc, char **argv)); +uint32_t chibiCmdStr2Num(char *str, uint8_t base); + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/chibiUsrCfg.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/chibiUsrCfg.h new file mode 100644 index 0000000..f0c7fc7 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/chibiUsrCfg.h @@ -0,0 +1,299 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +/*! + \file + \ingroup + + This is the user configurable file. It contains parameters that users + can change to suit their needs. + +*/ +/**************************************************************************/ +#ifndef CHB_USR_CFG_H +#define CHB_USR_CFG_H + +/**************************************************************************/ +/*! + Normally, when data is received to the radio, the radio will issue an interrupt + to the microcontroller(MCU). The MCU will then move the data from the radio + to the MCU memory. This needs to be done as quickly as possible since any other + frame received by the radio will overwrite the previous one. Hence the data is + moved inside the interrupt service routine. + + In some cases, this is not desired, especially if there are other devices that are + extremely busy and have tight timing requirements. In this case, RX POLLING MODE + will simply flag the interrupt and the data will get moved at the next possible chance + by the MCU. Its called RX POLLING MODE because the interrupt flag is checked + outside of the interrupt service routine on each iteration of the main loop (polling). + + RX POLLING MODE also resolves an issue with the Arduino Ethernet shield where the + software makes it incompatible with devices that access the SPI bus inside an + interrupt service routine. + + Value Polling Mode + 0x0 Disable (Default) + 0x1 Enable + + +*/ +/**************************************************************************/ +#define CHB_RX_POLLING_MODE 0 + +/**************************************************************************/ +/*! + Enable the chibiArduino stack to run in promiscuous mode. This should + only be used to analyze raw packet frames, like for wireshark. +*/ +/**************************************************************************/ +#define CHIBI_PROMISCUOUS 0 + +/**************************************************************************/ +/*! + Max payload determines the largest size that can be transmitted in a single frame. + If a frame is transmitted that's greater than the max payload, then it + will be split up into the max payload size and transmitted over multiple frames. + + Integer, byte(s); Range: 1 - 116; Default: 100 + NOTE values over 100 may not work. Please see the documentation. + +*/ +/**************************************************************************/ +#define CHB_MAX_PAYLOAD 100 + +/**************************************************************************/ +/*! + This is the position in EEPROM where the 64-bit IEEE address is stored. + It takes up 8 byte positions in the EEPROM. + + HEX, EEPROM location; Range: 0x00 - 0x01F8; Default: 0x00 +*/ +/**************************************************************************/ +#define CHB_EEPROM_IEEE_ADDR 0x00 + +/**************************************************************************/ +/*! + This is the position in the EEPROM where the 16-bit short address is + stored. It takes up 2 bytes in the EEPROM. + + HEX, EEPROM location; Range: 0x00 - 0x1FE; Default 0x09 +*/ +/**************************************************************************/ +#define CHB_EEPROM_SHORT_ADDR 0x09 + +/**************************************************************************/ +/*! + This is where the SLP_TR pin is defined. The PORT, Data Direction register + and the position is needed to fully define it. + + CHB_SLPTR_PORT default PORTC on the chibiduino + CHB_SLPTR_DDIR default DDRC on the chibiduino + CHB_SLPTR_PIN default 2 on the chibiduino. +*/ +/**************************************************************************/ +#define CHB_SLPTR_PORT PORTC +#define CHB_SLPTR_DDIR DDRC +#define CHB_SLPTR_PIN 2 + +/**************************************************************************/ +/*! + This is where the SPI Chip Select pin is defined. The PORT, Data Direction register + and the position is needed to fully define it. + + CHB_SPI_CS_PORT default PORTC on the chibiduino + CHB_SPI_CS_DDIR default DDRC on the chibiduino + CHB_SPI_CS_PIN default 3 on the chibiduino. +*/ +/**************************************************************************/ +#define CHB_SPI_CS_PORT PORTC +#define CHB_SPI_CS_DDIR DDRC +#define CHB_SPI_CS_PIN 3 // PC.3 - SPI Chip Select (SSEL) + + +/**************************************************************************/ +/*! + This is where the IRQ vector is defined. The IRQ vector will be based + on the interrupt being used for the radio. + + CHB_RADIO_IRQ default PCINT0_vect on the chibiduino +*/ +/**************************************************************************/ +#define CHB_RADIO_IRQ PCINT0_vect + +/**************************************************************************/ +/*! + This is where the interrupt configuration code is. This may be different + based on the chip or type of interrupt being used. +*/ +/**************************************************************************/ +// enable rising edge interrupt on IRQ0 +#define CFG_CHB_INTP() do \ + { \ + PCMSK0 |= _BV(PCINT6); \ + PCICR |= _BV(PCIE0); \ + } \ + while(0) + +/**************************************************************************/ +/*! + This is the code to enable and disable the interrupts on the MCU side. + This is only used when we're in RX_POLLING_MODE where the interrupt needs + to be turned off on the MCU side until the data can be retrieved. It also + is a workaround for a nasty bug on the Wiznet W5100 chips where the + SPI interface is not released properly. Hence, the interrupts are turned + off until the SPI bus is free and the data can be retrieved without collision. +*/ +/**************************************************************************/ +#define CHB_IRQ_DISABLE() do {PCMSK0 &= ~_BV(PCINT6);} while(0) +#define CHB_IRQ_ENABLE() do {PCMSK0 |= _BV(PCINT6);} while(0) + + +/**************************************************************************/ +/*! + The default channel for the radio to start on. The 802.15.4 channels go from + channel 11 to 26. Channels that don't conflict with 802.11 (Wi-Fi) are + channels 15, 20, and 26 in North America and Europe. + + Integer; Range: 11 - 26; Default: 11 +*/ +/**************************************************************************/ +#define CHB_CHANNEL 11 + +/**************************************************************************/ +/*! + This is the default PAN ID (network ID) of all devices on the network. + Only devices sharing the same PAN ID can communicate with each other, + unless the radio is set to promiscuous mode. The PAN ID is a 16-bit value. + + HEX; Range: 0x0000 - 0xFFFF; Default: 0x1234 +*/ +/**************************************************************************/ +#define CHB_PAN_ID 0x1234 + +/**************************************************************************/ +/*! + This is the value that gets written into the radio's register. Each value + corresponds to a different transmit power in dBm. The mapping is as follows: + + Value Power (dBm) + 0x0 +3.0 (Default) + 0x1 +2.6 + 0x2 +2.1 + 0x3 +1.6 + 0x4 +1.1 + 0x5 +0.5 + 0x6 -0.2 + 0x7 -1.2 + 0x8 -2.2 + 0x9 -3.2 + 0xA -4.2 +*/ +/**************************************************************************/ +#define CHB_TX_PWR 0x0 + +/**************************************************************************/ +/*! + This is the number of times the radio will auto-retry a transmission. + The auto-retry is triggered when an ACK isn't received within the ACK + timeout period. This is typically ~1 msec. + + Integer, count; Range: 0 - 15; Default: 3 +*/ +/**************************************************************************/ +#define CHB_MAX_FRAME_RETRIES 3 + +/**************************************************************************/ +/*! + This is the number of times the radio will attempt a transmission when + the channel is busy. The radio first checks if the channel is clear. + If it's occupied by another node, then it will back-off for a random + period and try again. If it exceeds the MAX CSMA RETRIES, it will assume + the channel is blocked and return an error status. + + Integer, count; Range: 0 - 9; Default: 4 +*/ +/**************************************************************************/ +#define CHB_MAX_CSMA_RETRIES 4 + +/**************************************************************************/ +/*! + This is the minimum backoff exponent. When the channel is busy, the radio + will wait at least 2^MIN_BE symbol periods before another attempt at + transmission. + + Integer, exponent; Range: 0 - 3; Default: 0 +*/ +/**************************************************************************/ +#define CHB_MIN_BE 0 + +/**************************************************************************/ +/*! + This is the clear channel assessment mode used to determine whether a + channel is clear or not. There are generally two ways to assess a busy + channel. One is to do an energy detection by sampling the energy level + of the channel. If its below the threshold, then its clear. The other + way is to check for a 2.4 GHz carrier signal. + + Value Mode + 0 Reserved + 1 Mode 1, Energy above threshold (Default) + 2 Mode 2, Carrier sense only + 3 Mode 3, Carrier sense with energy above threshold +*/ +/**************************************************************************/ +#define CHB_CCA_MODE 0x1 + +/**************************************************************************/ +/*! + This is the energy detection threshold for the clear channel assessment. + A channel is considered busy when the energy in the channel is: + RSSI_BASE_VAL + 2 CCA_ED_THRES [dBm] + + where RSSI_BASE_VAL = -91 dBm for the AT86RF230 + + Integer, byte; Range: 0x01 - 0x0F; Default: 0x07 +*/ +/**************************************************************************/ +#define CHB_CCA_ED_THRES 0x7 + +/**************************************************************************/ +/*! + These are the seeds to start off the pseudorandom number generator + for the backoff timer. They can be defined to be anything and will + determine the random number sequence for the backoffs. +*/ +/**************************************************************************/ +#define CHB_CSMA_SEED0 0 +#define CHB_CSMA_SEED1 0 + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex1_hello_world1/chibi_ex1_hello_world1.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex1_hello_world1/chibi_ex1_hello_world1.pde new file mode 100644 index 0000000..a82e903 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex1_hello_world1/chibi_ex1_hello_world1.pde @@ -0,0 +1,25 @@ +/* Chibi for Arduino, Example 1 +This is a very basic sketch that shows how to transmit data. The data being +transmitted is the standard "hello world" message. The destination address will +be a broadcast address so any node within listening range will hear it. There is +also a delay of 500 msec between each transmission. +*/ + +#include + +byte msg[] = "Hello World"; + +void setup() +{ + chibiInit(); +} + +void loop() +{ + // We're going to add 1 to the message length to handle the terminating null + // character for a string '/0'. + chibiTx(BROADCAST_ADDR, msg, 12); + + // delay half a second between transmission + delay(500); +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex2_hello_world2/chibi_ex2_hello_world2.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex2_hello_world2/chibi_ex2_hello_world2.pde new file mode 100644 index 0000000..b21c346 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex2_hello_world2/chibi_ex2_hello_world2.pde @@ -0,0 +1,38 @@ +/* Chibi for Arduino, Example 2 +This is the same Hello World example except that both +transmit and receive handling is included. +*/ + +#include + +byte msg[] = "Hello World"; + +void setup() +{ + Serial.begin(57600); + chibiInit(); +} + +void loop() +{ + // We're going to add 1 to the message length to handle the + // terminating character '/0'. We're also sending a broadcast so + // any node in listening range will hear the message. + chibiTx(BROADCAST_ADDR, msg, 12); + + // if any data is received, then print it to the terminal + if (chibiDataRcvd() == true) + { + byte buf[CHB_MAX_PAYLOAD]; // store the received data in here + + chibiGetData(buf); + + // The data consists of ASCII characters in byte (unsigned char) format. The print + // function requires ASCII characters be in char format so we need to inform the function + // that its okay to convert the format from unsigned char to char. + Serial.print((char *)buf); + } + + // delay half a second between transmission + delay(500); +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex3_hello_world3/chibi_ex3_hello_world3.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex3_hello_world3/chibi_ex3_hello_world3.pde new file mode 100644 index 0000000..3fded25 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex3_hello_world3/chibi_ex3_hello_world3.pde @@ -0,0 +1,43 @@ +/* Chibi for Arduino, Example 3 +This example is the same as the previous examples except that it +changes the channel to one that is not occupied by any 802.11 Wi-Fi +device. Its basically just to show how to change the channel. +*/ + +#include + +byte msg[] = "Hello World"; +byte buf[CHB_MAX_PAYLOAD]; + +void setup() +{ + Serial.begin(57600); + + // Init the chibi wireless stack + chibiInit(); + + // set the channel to channel 20. channel 20 is out of band of + // 802.11 wi-fi channels + chibiSetChannel(20); +} + +void loop() +{ + // We're going to automatically calculate the length + // of the message string using strlen(). We add 1 to the + // length to handle the terminating character '/0'. + // We're also sending a broadcast so any node in listening + // range will hear the message. + chibiTx(BROADCAST_ADDR, msg, 12); + + // We're going to print anything we receive in case there are others + // transmitting. + if (chibiDataRcvd() == true) + { + chibiGetData(buf); + Serial.println((char *)buf); + } + + // delay half a second between transmission + delay(500); +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex4_cmdline/chibi_ex4_cmdline.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex4_cmdline/chibi_ex4_cmdline.pde new file mode 100644 index 0000000..8718a1c --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex4_cmdline/chibi_ex4_cmdline.pde @@ -0,0 +1,139 @@ +/* Chibi for Arduino, Example 4 +This example shows how to use the command line parser integrated into chibi. It's +very useful for interactive control of a node, especially for testing and experimentation. +You can define your own commands to transmit, read registers, toggle I/O pins, etc. + +There's a function at the bottom called strCat(..) that might look kind of complicated. +It just takes in an array of strings and concatenates (connects) them together. This is +because the command line parser chops up anything typed into the command line into a string array +with the space as the delimiter. The strCat function just takes the string array and puts them all back +together. +*/ + +#include + +/**************************************************************************/ +// Initialize +/**************************************************************************/ +void setup() +{ + // Initialize the chibi command line and set the speed to 57600 bps + chibiCmdInit(57600); + + // Initialize the chibi wireless stack + chibiInit(); + + // This is where you declare the commands for the command line. + // The first argument is the alias you type in the command line. The second + // argument is the name of the function that the command will jump to. + + chibiCmdAdd("getsaddr", cmdGetShortAddr); // set the short address of the node + chibiCmdAdd("setsaddr", cmdSetShortAddr); // get the short address of the node + chibiCmdAdd("send", cmdSend); // send the string typed into the command line +} + +/**************************************************************************/ +// Loop +/**************************************************************************/ +void loop() +{ + // This function checks the command line to see if anything new was typed. + chibiCmdPoll(); + + // Check if any data was received from the radio. If so, then handle it. + if (chibiDataRcvd() == true) + { + int len, rssi, src_addr; + byte buf[100]; // this is where we store the received data + + // retrieve the data and the signal strength + len = chibiGetData(buf); + rssi = chibiGetRSSI(); + src_addr = chibiGetSrcAddr(); + + // Print out the message and the signal strength + Serial.print("Message received from node 0x"); + Serial.print(src_addr, HEX); + Serial.print(": "); + Serial.print((char *)buf); + Serial.print(", RSSI = 0x"); Serial.println(rssi, HEX); + } +} + +/**************************************************************************/ +// USER FUNCTIONS +/**************************************************************************/ + +/**************************************************************************/ +/*! + Get short address of device from EEPROM + Usage: getsaddr +*/ +/**************************************************************************/ +void cmdGetShortAddr(int arg_cnt, char **args) +{ + int val; + + val = chibiGetShortAddr(); + Serial.print("Short Address: "); Serial.println(val, HEX); +} + +/**************************************************************************/ +/*! + Write short address of device to EEPROM + Usage: setsaddr +*/ +/**************************************************************************/ +void cmdSetShortAddr(int arg_cnt, char **args) +{ + int val; + + val = chibiCmdStr2Num(args[1], 16); + chibiSetShortAddr(val); +} + +/**************************************************************************/ +/*! + Transmit data to another node wirelessly using Chibi stack. Currently + only handles ASCII string payload + Usage: send +*/ +/**************************************************************************/ +void cmdSend(int arg_cnt, char **args) +{ + byte data[100]; + int addr, len; + + // convert cmd line string to integer with specified base + addr = chibiCmdStr2Num(args[1], 16); + + // concatenate strings typed into the command line and send it to + // the specified address + len = strCat((char *)data, 2, arg_cnt, args); + chibiTx(addr, data,len); +} + +/**************************************************************************/ +/*! + Concatenate multiple strings from the command line starting from the + given index into one long string separated by spaces. +*/ +/**************************************************************************/ +int strCat(char *buf, unsigned char index, char arg_cnt, char **args) +{ + uint8_t i, len; + char *data_ptr; + + data_ptr = buf; + for (i=0; i + Note: the LED brightness value must be a number between 0 and 255 +*/ +/************************************************************/ +#include + +/**************************************************************************/ +// Initialize +/**************************************************************************/ +void setup() +{ + pinMode(9, OUTPUT); // declare pin 9 to be an output + analogWrite(9, 0); // initialize pin 9 to have a brightness of 0 + + chibiCmdInit(57600); // initialize the chibi command line to 57600 bps + chibiInit(); + + chibiCmdAdd("led", cmdLed); // send servo position to remote node + chibiCmdAdd("getsaddr", cmdGetShortAddr); // set the short address of the node + chibiCmdAdd("setsaddr", cmdSetShortAddr); // get the short address of the node +} + +/**************************************************************************/ +// Loop +/**************************************************************************/ +void loop() { + chibiCmdPoll(); // poll the command line for any user input from the serial port + + if (chibiDataRcvd()) + { + byte val, buf[CHB_MAX_PAYLOAD]; + chibiGetData(buf); + + // Its assumed that the data will be in the first byte of the data + val = buf[0]; + analogWrite(9, val); + + // Print out the position value that the servo will be moved to + Serial.print("LED Brightness = "); Serial.println(val, DEC); + } +} + +/**************************************************************************/ +// USER FUNCTIONS +/**************************************************************************/ + +/**************************************************************************/ +/*! + Send data to control the servo. + Usage: servo +*/ +/**************************************************************************/ +void cmdLed(int argc, char **argv) +{ + unsigned int addr; + byte ledVal, data[1]; + + // argv[1] is the first argument entered into the command line. This should + // be the destination address of the remote node we want to send the command to. + // The address is always a hexadecimal value. + addr = chibiCmdStr2Num(argv[1], 16); + + // argv[2] is the second argument entered into the command line. This should + // be the servo position. We're going to send this data to the remote node. + ledVal = chibiCmdStr2Num(argv[2], 10); + data[0] = ledVal; + + // Send out the data + chibiTx(addr, data, 1); +} + +/**************************************************************************/ +/*! + Get short address of device from EEPROM + Usage: getsaddr +*/ +/**************************************************************************/ +void cmdGetShortAddr(int arg_cnt, char **args) +{ + int val; + + val = chibiGetShortAddr(); + Serial.print("Short Address: "); Serial.println(val, HEX); +} + +/**************************************************************************/ +/*! + Write short address of device to EEPROM + Usage: setsaddr +*/ +/**************************************************************************/ +void cmdSetShortAddr(int arg_cnt, char **args) +{ + int val; + + val = chibiCmdStr2Num(args[1], 16); + chibiSetShortAddr(val); +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex6_servo/chibi_ex6_servo.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex6_servo/chibi_ex6_servo.pde new file mode 100644 index 0000000..72b5d36 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex6_servo/chibi_ex6_servo.pde @@ -0,0 +1,124 @@ +/************************************************************/ +/* + Chibi Servo Example + This is an example of controlling a servo wirelessly. The command + line is implemented along with three commands: servo, getsaddr, setsaddr. + "getsaddr" gets the address of the node. "setsaddr" sets the address + of the node. Each of the nodes should be set with a unique 16-bit + address. The servo command will move the servo on the remote node. There + is also a printout on each node for the received servo position. It can + be viewed by connecting the node to a serial terminal program. + + Directions for use: + 1. Load two nodes with this software. + 2. Set unique addresses for each node. + 3. Connect servo up to 5V, GND, and digital pin 9. + 4. Connect to at least one node via serial terminal program, ie: Teraterm + 5. Send servo command to remote node: + servo + Note: the servo position must be a number between 0 and 180 +*/ +/************************************************************/ + +#include +#include + +Servo myservo; // create servo object to control a servo + // a maximum of eight servo objects can be created + +/**************************************************************************/ +// Initialize +/**************************************************************************/ +void setup() +{ + myservo.attach(9); // attaches the servo on pin 9 to the servo object + myservo.write(0); // set the servo to the 0 degree position + + chibiCmdInit(57600); // initialize the chibi command line to 57600 bps + chibiInit(); + + chibiCmdAdd("servo", cmdServo); // send servo position to remote node + chibiCmdAdd("getsaddr", cmdGetShortAddr); // set the short address of the node + chibiCmdAdd("setsaddr", cmdSetShortAddr); // get the short address of the node +} + +/**************************************************************************/ +// Loop +/**************************************************************************/ +void loop() +{ + chibiCmdPoll(); // poll the command line for any user input from the serial port + + if (chibiDataRcvd()) + { + byte len, pos, buf[CHB_MAX_PAYLOAD]; + len = chibiGetData(buf); + + // Its assumed that the data will be in the first byte of the data + pos = buf[0]; + if ((pos >= 0) && (pos <=180)) + { + myservo.write(pos); + } + + // Print out the position value that the servo will be moved to + Serial.print("Servo = "); Serial.println(pos, DEC); + } +} + +/**************************************************************************/ +// USER FUNCTIONS +/**************************************************************************/ + +/**************************************************************************/ +/*! + Send data to control the servo. + Usage: servo +*/ +/**************************************************************************/ +void cmdServo(int argc, char **argv) +{ + unsigned int addr; + byte servo_pos, data[1]; + + // argv[1] is the first argument entered into the command line. This should + // be the destination address of the remote node we want to send the command to. + // The address is always a hexadecimal value. + addr = chibiCmdStr2Num(argv[1], 16); + + // argv[2] is the second argument entered into the command line. This should + // be the servo position. We're going to send this data to the remote node. + servo_pos = chibiCmdStr2Num(argv[2], 10); + data[0] = servo_pos; + + // Send out the data + chibiTx(addr, data, 1); +} + +/**************************************************************************/ +/*! + Get short address of device from EEPROM + Usage: getsaddr +*/ +/**************************************************************************/ +void cmdGetShortAddr(int arg_cnt, char **args) +{ + int val; + + val = chibiGetShortAddr(); + Serial.print("Short Address: "); Serial.println(val, HEX); +} + +/**************************************************************************/ +/*! + Write short address of device to EEPROM + Usage: setsaddr +*/ +/**************************************************************************/ +void cmdSetShortAddr(int arg_cnt, char **args) +{ + int val; + + val = chibiCmdStr2Num(args[1], 16); + chibiSetShortAddr(val); +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex7_webserver/chibi_ex7_webserver.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex7_webserver/chibi_ex7_webserver.pde new file mode 100644 index 0000000..90a947b --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex7_webserver/chibi_ex7_webserver.pde @@ -0,0 +1,257 @@ +/******************************************************************/ +/* + Chibi Web Server + This is a modification of the original web server file that comes + in the Arduino Ethernet library. Its purpose is to demonstrate how + to use the Chibi library with the Arduino Ethernet library. + + We're only checking analog channels 0, 1, 4, and 5. Analog channels + 2 and 3 are being used for the wireless radio. + + In order to run both libraries at the same time, either + CHB_RX_POLLING_MODE needs to be set to 1 in chibiUsrCfg.h or the + Arduino ethernet code needs to be changed to protect the Wiznet + chip accesses from interrupts. The reason is that there is a hardware + bug in the Wiznet W5100 chip that doesn't it allow it to share + the SPI bus properly. For more info, check out this application note from + Wiznet: + + http://bit.ly/bENS6J + + A tutorial on how to do this should be available soon on the FreakLabs site. + + Directions: + 1. Load two nodes with this software. Put an ethernet shield on one of the nodes. + 2. Set unique chibi addresses for each node using the "setsaddr" command. + 3. Connect networked ethernet cable to ethernet shield. + 4. Get on PC and set browser to connect to node: + Ex: if node address is 192.168.0.30, type: + http://192.168.0.30 in URL bar + 5. Connect to non-ethernet node via serial terminal, ie: Teraterm + 6. Use the "send" command to send a message to the ethernet node: + send + ex: send 1234 hello world i love you + 6. Refresh browser. You should see the message in the browser window. +*/ +/******************************************************************/ + +/* + Web Server + + A simple web server that shows the value of the analog input pins. + using an Arduino Wiznet Ethernet shield. + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + + created 18 Dec 2009 + by David A. Mellis + modified 4 Sep 2010 + by Tom Igoe + + */ + +#include +#include +#include + +/**************************************************************************/ +// Globals +/**************************************************************************/ + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network: +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +byte ip[] = { 192,168,0, 30 }; + +// Initialize the Ethernet server library +// with the IP address and port you want to use +// (port 80 is default for HTTP): +Server server(80); +static int prev; + +// These are for the chibi stack. +byte buf[CHB_MAX_PAYLOAD]; // hold the received data +byte len; // hold the length of the received data +byte rssi; // the signal strength of the received data + +/**************************************************************************/ +// Initialize +/**************************************************************************/ +void setup() +{ + // Initialize the chibi command line and set the speed to 57600 bps + chibiCmdInit(57600); + + // Add commands to the command table + chibiCmdAdd("getsaddr", cmdGetShortAddr); // set the short address of the node + chibiCmdAdd("setsaddr", cmdSetShortAddr); // get the short address of the node + chibiCmdAdd("send", cmdSend); // send the string typed into the command line + + // Initialize the chibi wireless stack + chibiInit(); + + // start the Ethernet connection and the server: + Ethernet.begin(mac, ip); + server.begin(); +} + +/**************************************************************************/ +// Loop +/**************************************************************************/ +void loop() +{ + // listen for incoming clients + Client client = server.available(); + if (client) { + + // an http request ends with a blank line + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + + // We're adding the chibi receive function here as well as in the + // main loop. Otherwise, when a client (browser) connects, then its possible + // that a long time can elapse before we exit this loop. This means + // that there's a high potential to lose data. + chibiRcv(); + + char c = client.read(); + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the http request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + // send a standard http response header + client.println("HTTP/1.1 200 OK"); + client.println("Content-Type: text/html"); + client.println(); + + // output the value of each analog input pin + client.print("Message received: "); client.print((char *)buf); + client.print(", RSSI = 0x"); client.println(rssi, HEX); + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } + else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + + } + // give the web browser time to receive the data + delay(1); + // close the connection: + client.stop(); + } + + // Poll the command line to check if any new data has arrived via the + // serial interface. + chibiCmdPoll(); + + // Handle any received data on the wireless interface. + chibiRcv(); + +} + +/**************************************************************************/ +// USER FUNCTIONS +/**************************************************************************/ + +/**************************************************************************/ +/*! + The Chibi receive function has been moved into this function since we're + using it in two places. That way, it removes the need to duplicate code + and is also better in terms of flash usage. +*/ +/**************************************************************************/ +void chibiRcv() +{ + if (chibiDataRcvd() == true) + { + len = chibiGetData(buf); + rssi = chibiGetRSSI(); + + // Print out the message and the signal strength + Serial.print("Message received: "); Serial.print((char *)buf); + Serial.print(", RSSI = 0x"); Serial.println(rssi, HEX); + } +} + +/**************************************************************************/ +/*! + Get short address of device from EEPROM + Usage: getsaddr +*/ +/**************************************************************************/ +void cmdGetShortAddr(int arg_cnt, char **args) +{ + int val; + + val = chibiGetShortAddr(); + Serial.print("Short Address: "); Serial.println(val, HEX); +} + +/**************************************************************************/ +/*! + Write short address of device to EEPROM + Usage: setsaddr +*/ +/**************************************************************************/ +void cmdSetShortAddr(int arg_cnt, char **args) +{ + int val; + + val = chibiCmdStr2Num(args[1], 16); + chibiSetShortAddr(val); +} + +/**************************************************************************/ +/*! + Transmit data to another node wirelessly using Chibi stack. Currently + only handles ASCII string payload + Usage: send +*/ +/**************************************************************************/ +void cmdSend(int arg_cnt, char **args) +{ + byte data[100]; + int addr, len; + + // convert cmd line string to integer with specified base + addr = chibiCmdStr2Num(args[1], 16); + + // concatenate strings typed into the command line and send it to + // the specified address + len = strCat((char *)data, 2, arg_cnt, args); + chibiTx(addr, data,len); +} + +/**************************************************************************/ +/*! + Concatenate multiple strings from the command line starting from the + given index into one long string separated by spaces. +*/ +/**************************************************************************/ +int strCat(char *buf, unsigned char index, char arg_cnt, char **args) +{ + uint8_t i, len; + char *data_ptr; + + data_ptr = buf; + for (i=0; i + +// These are general definitions. There are three main things to define +// in this sketch: where the LED is at, where the button is at, and where +// the data will be sent. +#define DEST_ADDR 3 // the destination address data will be sent to +#define LED_PIN 9 // the pin that will control the LED +#define BUTTON_PIN 8 // the pin that will detect the button + +// These two definitions will change based on the user hardware. If +// the idle (UP) position of the button is 0, then set BUTTON_UP to 0 and +// BUTTON_DOWN to 1. And vice-versa +#define BUTTON_DOWN 0 // the value that a button press generates on button pin +#define BUTTON_UP 1 // the value that a button release generates on button pin + +// These are the commands. More commands can be added based on the user inputs. +// Then they can be handled in the command handler function. +#define CMD_LED_OFF 0 // turn the LED off +#define CMD_LED_ON 1 // turn the LED on + +// Store the previous state of the button here. We'll use it to compare against +// the current button state to see if any event occurred. +byte button_state; + +/**************************************************************************/ +// Initialize +/**************************************************************************/ +void setup() +{ + // init the hardware + pinMode(LED_PIN, OUTPUT); + pinMode(BUTTON_PIN, INPUT); + + // init the wireless stack + chibiInit(); + + // init the serial port for debug purposes + Serial.begin(57600); + + // initial state of button is set to be unpushed + button_state = BUTTON_UP; +} + +/**************************************************************************/ +// Loop +/**************************************************************************/ +void loop() +{ + button_handler(); + command_handler(); +} + +/**************************************************************************/ +/*! + This function handles any button events. When the button changes state, like + if it gets pressed or released, then this function will detect it and send + out a command to change the LED on the remote node. +*/ +/**************************************************************************/ +void button_handler() +{ + byte button_val, data[1]; + + // get the button value from the input + button_val = digitalRead(BUTTON_PIN); + + // check if the button has changed state. compare the current button value + // with the previous value. if its the same, then ignore. if not, then handle + // the event. + if (button_val != button_state) + { + if (button_val == BUTTON_DOWN) + { + //the button has been pushed. Send out a command to turn the LED on. then + // update the button's state for future comparison + button_state = BUTTON_DOWN; + data[0] = CMD_LED_ON; + Serial.println("Button is down."); + } + else + { + // the button has been released. Send out a command to turn the LED off. then + // update the button's state for future comparison + button_state = BUTTON_UP; + data[0] = CMD_LED_OFF; + Serial.println("Button is up."); + } + chibiTx(DEST_ADDR, data, 1); + } +} +/**************************************************************************/ +/*! + This is the command handler. I wrote it semi-generically so it can be extended + to handle other commands. There are two main parts to it. The first part is to + retrieve any data that arrived wirelessly and extract the command. The second + part is to handle the command. + + In a real application, there might be multiple buttons or other input devices + that can trigger many different commands. In this case, you just need to add + each command to the switch statement and the code to handle it. +*/ +/**************************************************************************/ +void command_handler() +{ + byte cmd, buf[CHB_MAX_PAYLOAD]; + + // check to see if any new data has been received. if so, then we need to handle it. + if (chibiDataRcvd()) + { + // retrieve the data from the chibi stack + chibiGetData(buf); + + // its assumed that the data will be in the first byte of the buffer since we're only + // sending one byte. + cmd = buf[0]; + + // this is the main command handler. it deals with any commands that arrive through the radio. + switch (cmd) + { + case CMD_LED_OFF: + digitalWrite(LED_PIN, 0); + Serial.println("Command: LED OFF"); + break; + + case CMD_LED_ON: + digitalWrite(LED_PIN, 1); + Serial.println("Command: LED ON"); + break; + } + } +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex9_wsbridge/chibi_ex9_wsbridge.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex9_wsbridge/chibi_ex9_wsbridge.pde new file mode 100644 index 0000000..30637af --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/examples/chibi_ex9_wsbridge/chibi_ex9_wsbridge.pde @@ -0,0 +1,55 @@ +/* chibiArduino Wireshark Bridge, Example 9 +This sketch enables promiscuous mode on the Freakduino boards and dumps +the raw 802.15.4 frames out to the serial port. It should be used in +conjunction with the FreakLabs "wsbridge" application to feed the raw +frames into Wireshark. + +Before using this sketch, please go into the chibiUsrCfg.h file and +enable promiscuous mode. To do this, change the definition: + +#define CHIBI_PROMISCUOUS 0 +to +#define CHIBI_PROMISCUOUS 1 + +When not using promiscuous mode, please disable this setting by changing +it back to 0. +*/ + +#include + +/**************************************************************************/ +// Initialize +/**************************************************************************/ +void setup() +{ + // Init the chibi stack + chibiInit(); + + // Open the serial port at specified speed. For sniffing, we want to send data + // out the serial port as quickly as possible. On windows, 250kbps can be used. + // On linux, it only seems to like standard speeds up to 115200. To make things + // compatible on both platforms, I'm keeping the speed at 115200. If you want + // to boost the speed on a Windows system, use 250000 rather than 115200. + // Ex: Serial.begin(250000); + // + // Remember: If you change the speed here, make sure you change it on the application + // program as well. + Serial.begin(115200); +} + +/**************************************************************************/ +// Loop +/**************************************************************************/ +void loop() +{ + // Check if any data was received from the radio. If so, then handle it. + if (chibiDataRcvd() == true) + { + int len; + byte buf[CHB_MAX_PAYLOAD]; + + // send the raw data out the serial port in binary format + len = chibiGetData(buf); + Serial.write(buf, len); + } +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/keywords.txt b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/keywords.txt new file mode 100644 index 0000000..6cfc23b --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/keywords.txt @@ -0,0 +1,36 @@ +####################################### +# Syntax Coloring Map For CmdArduino +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +chibiInit KEYWORD2 +chibiSetShortAddr KEYWORD2 +chibiGetShortAddr KEYWORD2 +chibiSetIEEEAddr KEYWORD2 +chibiGetIEEEAddr KEYWORD2 +chibiRegRead KEYWORD2 +chibiRegWrite KEYWORD2 +chibiTx KEYWORD2 +chibiDataRcvd KEYWORD2 +chibiGetData KEYWORD2 +chibiGetRSSI KEYWORD2 +chibiGetSrcAddr KEYWORD2 +chibiSetChannel KEYWORD2 +chibiSleepRadio KEYWORD2 +chibiCmdInit KEYWORD2 +chibiCmdPoll KEYWORD2 +chibiCmdAdd KEYWORD2 +chibiCmdStr2Num KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### +BROADCAST_ADDR LITERAL1 + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb.c b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb.c new file mode 100644 index 0000000..0aaf7d8 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb.c @@ -0,0 +1,234 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +#include +#include + +#include "chb.h" +#include "chb_drvr.h" +#include "chb_buf.h" + +static pcb_t pcb; + +// these are for the duplicate checking and rejection +static U8 prev_seq = 0xFF; +static U16 prev_src_addr = 0xFFFE; + +/**************************************************************************/ +/*! + +*/ +/**************************************************************************/ +void chb_init() +{ + memset(&pcb, 0, sizeof(pcb_t)); + pcb.src_addr = chb_get_short_addr(); + chb_drvr_init(); +} + +/**************************************************************************/ +/*! + +*/ +/**************************************************************************/ +pcb_t *chb_get_pcb() +{ + return &pcb; +} + +/**************************************************************************/ +/*! + Requires the dest addr, location to store data, and len of payload. + Returns the length of the hdr. +*/ +/**************************************************************************/ +static U8 chb_gen_hdr(U8 *hdr, U16 addr, U8 len) +{ + U8 *hdr_ptr = hdr; + + // calc frame size and put in 0 position of array + // frame size = hdr sz + payload len + fcs len + *hdr_ptr++ = CHB_HDR_SZ + len + CHB_FCS_LEN; + + // use default fcf byte 0 val but test for ack request. we won't request + // ack if broadcast. all other cases we will. + *hdr_ptr++ = CHB_FCF_BYTE_0 | ((addr != 0xFFFF) << CHB_ACK_REQ_POS); + *hdr_ptr++ = CHB_FCF_BYTE_1; + + *hdr_ptr++ = pcb.seq++; + + // fill out dest pan ID, dest addr, src addr + *(U16 *)hdr_ptr = CHB_PAN_ID; + hdr_ptr += sizeof(U16); + *(U16 *)hdr_ptr = addr; + hdr_ptr += sizeof(U16); + *(U16 *)hdr_ptr = pcb.src_addr; + hdr_ptr += sizeof(U16); + + // return the len of the header + return hdr_ptr - hdr; +} + +/**************************************************************************/ +/*! + This is the main function that transmits the data array to the specified + address. +*/ +/**************************************************************************/ +U8 chb_write(U16 addr, U8 *data, U8 len) +{ + U8 status, frm_len, hdr_len, hdr[CHB_HDR_SZ + 1]; + + while (len > 0) + { + // calculate which frame len to use. if greater than max payload, split + // up operation. + frm_len = (len > CHB_MAX_PAYLOAD) ? CHB_MAX_PAYLOAD : len; + + // gen frame header + hdr_len = chb_gen_hdr(hdr, addr, frm_len); + + // send data to chip + status = chb_tx(hdr, data, frm_len); + + if (status != CHB_SUCCESS) + { + switch (status) + { + case RADIO_SUCCESS: + // fall through + case CHB_SUCCESS_DATA_PENDING: + pcb.txd_success++; + break; + + case CHB_NO_ACK: + pcb.txd_noack++; + break; + + case CHB_CHANNEL_ACCESS_FAILURE: + pcb.txd_channel_fail++; + break; + + default: + break; + } + return status; + } + + // adjust len and restart + len = len - frm_len; + } + + return CHB_SUCCESS; +} + +/**************************************************************************/ +/*! + Read data from the buffer. Need to pass in a buffer of at leasts max frame + size and two 16-bit containers for the src and dest addresses. + + The read function will automatically populate the addresses and the data with + the frm payload. It will then return the len of the payload. +*/ +/**************************************************************************/ +U8 chb_read(chb_rx_data_t *rx) +{ + U8 i, len, seq, *data_ptr; + + data_ptr = rx->data; + + // first byte is always len. check it to make sure + // we have a valid len byte. + if ((len = chb_buf_read()) > CHB_MAX_FRAME_LENGTH) + { + return 0; + } + *data_ptr++ = len; + + // load the rest of the data into buffer + for (i=0; idata + 3; // location of sequence number + seq = *data_ptr; + + // parse the buffer and extract the dest and src addresses + data_ptr = rx->data + 6; // location of dest addr + rx->dest_addr = *(U16 *)data_ptr; + data_ptr += sizeof(U16); + rx->src_addr = *(U16 *)data_ptr; + data_ptr += sizeof(U16); + + // if the data in the rx buf is 0, then clear the rx_flag. otherwise, keep it raised + if (!chb_buf_get_len()) + { + pcb.data_rcv = false; + } + +#if (CHIBI_PROMISCUOUS) + // if we're in promiscuous mode, we don't want to do any duplicate rejection and we don't want to move the payload + // to the front of the buffer. We want to capture the full frame so just keep the frame intact and return the length. + return len; +#else + // duplicate frame check (dupe check). we want to remove frames that have been already been received since they + // are just retries. + // note: this dupe check only removes duplicate frames from the previous transfer. if another frame from a different + // node comes in between the dupes, then the dupe will show up as a received frame. + if ((seq == prev_seq) && (rx->src_addr == prev_src_addr)) + { + // this is a duplicate frame from a retry. the remote node thinks we didn't receive + // it properly. discard. + return 0; + } + else + { + prev_seq = seq; + prev_src_addr = rx->src_addr; + } + + // move the payload down to the beginning of the data buffer + memmove(rx->data, data_ptr, len - CHB_HDR_SZ); + + // finally, return the len of the payload + return len - CHB_HDR_SZ - CHB_FCS_LEN; +#endif + +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb.h new file mode 100644 index 0000000..094a772 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb.h @@ -0,0 +1,100 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +#ifndef CHB_H +#define CHB_H + +#include "chibiUsrCfg.h" +#include "types.h" + +#define CHB_HDR_SZ 9 // FCF + seq + pan_id + dest_addr + src_addr (2 + 1 + 2 + 2 + 2) +#define CHB_FCS_LEN 2 + +// frame_type = data +// security enabled = false +// frame pending = false +// ack request = false +// pan ID compression = true +#define CHB_FCF_BYTE_0 0x41 + +// dest addr = 16-bit +// frame version = 802.15.4 (not 2003) +// src addr = 16-bit +#define CHB_FCF_BYTE_1 0x98 + +#define CHB_ACK_REQ_POS 5 + +enum +{ + CHB_SUCCESS = 0, + CHB_SUCCESS_DATA_PENDING = 1, + CHB_CHANNEL_ACCESS_FAILURE = 3, + CHB_NO_ACK = 5, + CHB_INVALID = 7 +}; + +typedef struct +{ + U16 src_addr; + U8 seq; + volatile bool data_rcv; + volatile bool tx_end; + + // stats + U16 rcvd_xfers; + U16 txd_success; + U16 txd_noack; + U16 txd_channel_fail; + U16 overflow; + U16 underrun; + U8 battlow; + U8 status; + U8 ed; + U8 crc; + U8 tx_busy; +} pcb_t; + +typedef struct +{ + U8 len; + U16 src_addr; + U16 dest_addr; + U8 *data; +} chb_rx_data_t; + +void chb_init(); +pcb_t *chb_get_pcb(); +U8 chb_write(U16 addr, U8 *data, U8 len); +U8 chb_read(chb_rx_data_t *rx); + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_buf.c b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_buf.c new file mode 100644 index 0000000..5624e58 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_buf.c @@ -0,0 +1,87 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +#include +#include "chb_buf.h" + +static U8 chb_buf[CHB_BUF_SZ]; +static U8 rd_ptr, wr_ptr, len; + +/**************************************************************************/ +/*! + +*/ +/**************************************************************************/ +void chb_buf_init() +{ + rd_ptr = 0; + wr_ptr = 0; + len = 0; +} + +/**************************************************************************/ +/*! + +*/ +/**************************************************************************/ +void chb_buf_write(U8 data) +{ + chb_buf[wr_ptr] = data; + wr_ptr = (wr_ptr + 1) % CHB_BUF_SZ; + len++; +} + +/**************************************************************************/ +/*! + +*/ +/**************************************************************************/ +U8 chb_buf_read() +{ + U8 data; + + data = chb_buf[rd_ptr]; + rd_ptr = (rd_ptr + 1) % CHB_BUF_SZ; + len--; + return data; +} + +/**************************************************************************/ +/*! + +*/ +/**************************************************************************/ +U8 chb_buf_get_len() +{ + return len; +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_buf.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_buf.h new file mode 100644 index 0000000..b453cf8 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_buf.h @@ -0,0 +1,56 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +#ifndef CHB_BUF_H +#define CHB_BUF_H + +#include "chibiUsrCfg.h" +#include "types.h" + +#if (CHIBI_PROMISCUOUS) + // if we're using promiscuous mode, we may end up capturing a lot of frames. + // crank up the buffer size to handle traffic spikes. + #define CHB_BUF_SZ 1024 +#else + // in normal mode, this is the buffer size to handle incoming frames. if there + // is a lot of traffic and you're getting buffer issues, then increase this + // value so that more frames can be held inside RAM + #define CHB_BUF_SZ 128 +#endif + +void chb_buf_init(); +void chb_buf_write(U8 data); +U8 chb_buf_read(); +U8 chb_buf_get_len(); + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_cmd.c b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_cmd.c new file mode 100644 index 0000000..df36c8a --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_cmd.c @@ -0,0 +1,236 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +/*! + \file Cmd.c + + This implements a simple command line interface for the Arduino so that + its possible to execute individual functions within the sketch. +*/ +/**************************************************************************/ +#include +#include "WProgram.h" +#include "HardwareSerial.h" +#include "chb_cmd.h" + +// command line message buffer and pointer +static uint8_t msg[MAX_MSG_SIZE]; +static uint8_t *msg_ptr; + +// linked list for command table +static cmd_t *cmd_tbl_list, *cmd_tbl; + +// text strings for command prompt (stored in flash) +const char cmd_banner[] PROGMEM = "*************** CHIBI *******************"; +const char cmd_prompt[] PROGMEM = "CHIBI >> "; +const char cmd_unrecog[] PROGMEM = "CHIBI: Command not recognized."; + +/**************************************************************************/ +/*! + Generate the main command prompt +*/ +/**************************************************************************/ +static void chb_cmd_display() +{ + char buf[50]; + + Serial.println(); + + strcpy_P(buf, cmd_banner); + Serial.println(buf); + + strcpy_P(buf, cmd_prompt); + Serial.print(buf); +} + +/**************************************************************************/ +/*! + Parse the command line. This function tokenizes the command input, then + searches for the command table entry associated with the commmand. Once found, + it will jump to the corresponding function. +*/ +/**************************************************************************/ +static void chb_cmd_parse(char *cmd) +{ + uint8_t argc, i = 0; + char *argv[30]; + char buf[50]; + cmd_t *cmd_entry; + + fflush(stdout); + + // parse the command line statement and break it up into space-delimited + // strings. the array of strings will be saved in the argv array. + argv[i] = strtok(cmd, " "); + do + { + argv[++i] = strtok(NULL, " "); + } while ((i < 30) && (argv[i] != NULL)); + + // save off the number of arguments for the particular command. + argc = i; + + // parse the command table for valid command. used argv[0] which is the + // actual command name typed in at the prompt + for (cmd_entry = cmd_tbl; cmd_entry != NULL; cmd_entry = cmd_entry->next) + { + if (!strcmp(argv[0], cmd_entry->cmd)) + { + cmd_entry->func(argc, argv); + chb_cmd_display(); + return; + } + } + + // command not recognized. print message and re-generate prompt. + strcpy_P(buf, cmd_unrecog); + Serial.println(buf); + + chb_cmd_display(); +} + +/**************************************************************************/ +/*! + This function processes the individual characters typed into the command + prompt. It saves them off into the message buffer unless its a "backspace" + or "enter" key. +*/ +/**************************************************************************/ +static void chb_cmd_handler() +{ + char c = Serial.read(); + + switch (c) + { + case '\r': + // terminate the msg and reset the msg ptr. then send + // it to the handler for processing. + *msg_ptr = '\0'; + Serial.print("\r\n"); + chb_cmd_parse((char *)msg); + msg_ptr = msg; + break; + + case '\b': + // backspace + Serial.print(c); + if (msg_ptr > msg) + { + msg_ptr--; + } + break; + + default: + // check to make sure we're not overflowing the message buffer + if ((msg_ptr - msg) < MAX_MSG_SIZE) + { + // normal character entered. add it to the buffer + Serial.print(c); + *msg_ptr++ = c; + } + break; + } +} + +/**************************************************************************/ +/*! + This function should be set inside the main loop. It needs to be called + constantly to check if there is any available input at the command prompt. +*/ +/**************************************************************************/ +void chb_cmd_poll() +{ + while (Serial.available()) + { + chb_cmd_handler(); + } +} + +/**************************************************************************/ +/*! + Initialize the command line interface. This sets the terminal speed and + and initializes things. +*/ +/**************************************************************************/ +void chb_cmd_init(uint32_t speed) +{ + // init the msg ptr + msg_ptr = msg; + + // init the command table + cmd_tbl_list = NULL; + + // set the serial speed + Serial.begin(speed); +} + +/**************************************************************************/ +/*! + Add a command to the command table. The commands should be added in + at the setup() portion of the sketch. +*/ +/**************************************************************************/ +void chb_cmd_add(char *name, void (*func)(int argc, char **argv)) +{ + // alloc memory for command struct + cmd_tbl = (cmd_t *)malloc(sizeof(cmd_t)); + + // alloc memory for command name + char *cmd_name = (char *)malloc(strlen(name)+1); + + // copy command name + strcpy(cmd_name, name); + + // terminate the command name + cmd_name[strlen(name)] = '\0'; + + // fill out structure + cmd_tbl->cmd = cmd_name; + cmd_tbl->func = func; + cmd_tbl->next = cmd_tbl_list; + cmd_tbl_list = cmd_tbl; +} + +/**************************************************************************/ +/*! + Convert a string to a number. The base must be specified, ie: "32" is a + different value in base 10 (decimal) and base 16 (hexadecimal). +*/ +/**************************************************************************/ +uint32_t chb_cmd_str2num(char *str, uint8_t base) +{ + return strtol(str, NULL, base); +} + + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_cmd.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_cmd.h new file mode 100644 index 0000000..124c7ad --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_cmd.h @@ -0,0 +1,61 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +/*! + \file + \ingroup + + +*/ +/**************************************************************************/ +#ifndef CMD_H +#define CMD_H + +#define MAX_MSG_SIZE 100 +#include + +// command line structure +typedef struct _cmd_t +{ + char *cmd; + void (*func)(int argc, char **argv); + struct _cmd_t *next; +} cmd_t; + +void cmd_init(uint32_t speed); +void cmd_poll(); +void cmd_add(char *name, void (*func)(int argc, char **argv)); +uint32_t cmd_str2num(char *str, uint8_t base); + +#endif //CMD_H + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_drvr.c b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_drvr.c new file mode 100644 index 0000000..ea6bc9c --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_drvr.c @@ -0,0 +1,670 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +#include +#include "WProgram.h" +#include "chb.h" +#include "chb_drvr.h" +#include "chb_buf.h" +#include "chb_spi.h" +#include "chb_eeprom.h" + +#if (CHB_RX_POLLING_MODE) + #include "chb_rx_poll.h" +#else + #include "chb_rx_int.h" +#endif + +// do not print out any messages in non-promiscuous mode +#if (CHIBI_PROMISCUOUS) + const char chb_err_overflow[] PROGMEM = ""; + const char chb_err_init[] PROGMEM = ""; +#else + // store string messages in flash rather than RAM + const char chb_err_overflow[] PROGMEM = "BUFFER FULL. TOSSING INCOMING DATA\n"; + const char chb_err_init[] PROGMEM = "RADIO NOT INITIALIZED PROPERLY\n"; +#endif +/**************************************************************************/ +/*! + Retrieve the state from the radio's state machine register. +*/ +/**************************************************************************/ +static U8 chb_get_state() +{ + return chb_reg_read(TRX_STATUS) & 0x1f; +} + +/**************************************************************************/ +/*! + Retrieve the status of the last received frame. +*/ +/**************************************************************************/ +static U8 chb_get_status() +{ + return chb_reg_read(TRX_STATE) >> CHB_TRAC_STATUS_POS; +} + +/**************************************************************************/ +/*! + Perform a delay of the specified amount of microseconds. +*/ +/**************************************************************************/ +static void chb_delay_us(U16 usec) +{ + do + { + delayMicroseconds(usec); + } while (--usec); +} + +/**************************************************************************/ +/*! + Read the radio's registers for the specified address. Interrupts are disabled + for the duration of the reading to prevent an interrupt from interfering + with the operation. +*/ +/**************************************************************************/ +U8 chb_reg_read(U8 addr) +{ + U8 val = 0; + + /* Add the register read command to the register address. */ + addr |= 0x80; + + CHB_ENTER_CRIT(); + CHB_SPI_ENABLE(); + + /*Send Register address and read register content.*/ + val = chb_xfer_byte(addr); + val = chb_xfer_byte(val); + + CHB_SPI_DISABLE(); + CHB_LEAVE_CRIT(); + + return val; +} + +/**************************************************************************/ +/*! + Read a 16-bit register. This actually does two consecutive 8-bit reads + of contiguous registers. It's mostly used to retrieve the PAN ID or the + short address of the node. +*/ +/**************************************************************************/ +U16 chb_reg_read16(U8 addr) +{ + U8 i; + U16 val = 0; + + for (i=0; i<2; i++) + { + addr |= chb_reg_read(addr + i) << (8 * i); + } + return val; +} + +/**************************************************************************/ +/*! + Write to the radio's registers at the specified address with the specified + value. +*/ +/**************************************************************************/ +void chb_reg_write(U8 addr, U8 val) +{ + U8 dummy; + + /* Add the Register Write command to the address. */ + addr |= 0xC0; + + CHB_ENTER_CRIT(); + CHB_SPI_ENABLE(); + + /*Send Register address and write register content.*/ + dummy = chb_xfer_byte(addr); + dummy = chb_xfer_byte(val); + + CHB_SPI_DISABLE(); + CHB_LEAVE_CRIT(); +} + +/**************************************************************************/ +/*! + Write 16-bits to the radio's registers. This does two consecutive 8-bit + writes to contiguous memory addresses. +*/ +/**************************************************************************/ +void chb_reg_write16(U8 addr, U16 val) +{ + U8 i; + + for (i=0; i<2; i++) + { + chb_reg_write(addr + i, val >> (8 * i)); + } +} + +/**************************************************************************/ +/*! + Write 64-bits to the radio's registers. This does 8 consecutive 8-bit + writes to contiguous memory addresses. This is only used to write the + IEEE address in case it is used. The default for Chibi is just to use + 16-bit addressing. +*/ +/**************************************************************************/ +void chb_reg_write64(U8 addr, U8 *val) +{ + U8 i; + + for (i=0; i<8; i++) + { + chb_reg_write(addr + i, *(val + i)); + } +} + +/**************************************************************************/ +/*! + Perform a read/modify/write to a register. This function first reads + the specified register, then masks off the bits that will be modified. + It then changes the modified bits and then writes it back to the register. + It's used to modify registers without changing bits that are outside + of the mask. +*/ +/**************************************************************************/ +void chb_reg_read_mod_write(U8 addr, U8 val, U8 mask) +{ + U8 tmp; + + tmp = chb_reg_read(addr); + val &= mask; // mask off stray bits from val + tmp &= ~mask; // mask off bits in reg val + tmp |= val; // copy val into reg val + chb_reg_write(addr, tmp); // write back to reg +} + +/**************************************************************************/ +/*! + Write data to the frame FIFO of the radio. This is where the data to + be transmitted gets written. The frame data is written in two separate bursts. + The first burst is to write the frame header and the second burst is + to write the frame payload. Makes things easier this way. +*/ +/**************************************************************************/ +void chb_frame_write(U8 *hdr, U8 hdr_len, U8 *data, U8 data_len) +{ + U8 i, dummy; + + // dont allow transmission longer than max frame size + if ((hdr_len + data_len) > 127) + { + return; + } + + // initiate spi transaction + CHB_ENTER_CRIT(); + CHB_SPI_ENABLE(); + + // send fifo write command + dummy = chb_xfer_byte(CHB_SPI_CMD_FW); + + // write hdr contents to fifo + for (i=0; i= CHB_MIN_FRAME_LENGTH) && (len <= CHB_MAX_FRAME_LENGTH)) + { + // check to see if there is room to write the frame in the buffer. if not, then drop it + if (len < (CHB_BUF_SZ - chb_buf_get_len())) + { + chb_buf_write(len); + + for (i=0; ioverflow++; + + // grab the message from flash & print it out + strcpy_P(buf, chb_err_overflow); + Serial.print(buf); + } + } + + CHB_SPI_DISABLE(); + CHB_LEAVE_CRIT(); +} + +/**************************************************************************/ +/*! + Read directly from the SRAM on the radio. This is only used for debugging + purposes. +*/ +/**************************************************************************/ +#ifdef CHB_DEBUG +void chb_sram_read(U8 addr, U8 len, U8 *data) +{ + U8 i, dummy; + + CHB_ENTER_CRIT(); + CHB_SPI_ENABLE(); + + /*Send SRAM read command.*/ + dummy = chb_xfer_byte(CHB_SPI_CMD_SR); + + /*Send address where to start reading.*/ + dummy = chb_xfer_byte(addr); + + for (i=0; isrc_addr = addr; +} + +/**************************************************************************/ +/*! + Retrieves the 16-bit short address of the radio. +*/ +/**************************************************************************/ +U16 chb_get_short_addr() +{ + U8 addr[2]; + + chb_eeprom_read(CHB_EEPROM_SHORT_ADDR, addr, 2); + return *(U16 *)addr; +} + +/**************************************************************************/ +/*! + Set the channel for the radio. +*/ +/**************************************************************************/ +U8 chb_set_channel(U8 channel) +{ + U8 state; + + chb_reg_read_mod_write(PHY_CC_CCA, channel, 0x1f); + + // add a delay to allow the PLL to lock if in active mode. + state = chb_get_state(); + if ((state == RX_ON) || (state == PLL_ON)) + { + chb_delay_us(TIME_PLL_LOCK); + } + + return ((chb_reg_read(PHY_CC_CCA) & 0x1f) == channel) ? RADIO_SUCCESS : RADIO_TIMED_OUT; +} + +/**************************************************************************/ +/*! + Returns the current channel for the radio. +*/ +/**************************************************************************/ +U8 chb_get_channel() +{ + return (chb_reg_read(PHY_CC_CCA) & 0x1f); +} + +/**************************************************************************/ +/*! + Transmits a frame via the radio. It loads the data into the fifo, + initiates a transmission attempt and returns the status of the transmission + attempt. +*/ +/**************************************************************************/ +U8 chb_tx(U8 *hdr, U8 *data, U8 len) +{ + U8 state = chb_get_state(); + pcb_t *pcb = chb_get_pcb(); + + if ((state == BUSY_TX) || (state == BUSY_TX_ARET)) + { + return RADIO_WRONG_STATE; + } + + // transition to the Transmit state + chb_set_state(TX_ARET_ON); + + // write frame to buffer. first write header into buffer (add 1 for len byte), then data. + chb_frame_write(hdr, CHB_HDR_SZ + 1, data, len); + + //Do frame transmission. + pcb->tx_busy = true; + chb_reg_read_mod_write(TRX_STATE, CMD_TX_START, 0x1F); + + // wait for the transmission to end, signalled by the TRX END flag + while (!pcb->tx_end); + pcb->tx_end = false; + + // check the status of the transmission + return chb_get_status(); +} + +/**************************************************************************/ +/*! + Initialize the radio registers. +*/ +/**************************************************************************/ +static void chb_radio_init() +{ + U8 ieee_addr[8]; + + // disable intps while we config the radio + chb_reg_write(IRQ_MASK, 0); + + // force transceiver off while we configure the intps + chb_reg_read_mod_write(TRX_STATE, CMD_FORCE_TRX_OFF, 0x1F); + chb_delay_us(TIME_P_ON_TO_TRX_OFF); + + // set radio cfg parameters + // **note** uncomment if these will be set to something other than default + //chb_reg_read_mod_write(XAH_CTRL_0, CHB_MAX_FRAME_RETRIES << CHB_MAX_FRAME_RETRIES_POS, 0xF << CHB_MAX_FRAME_RETRIES_POS); + //chb_reg_read_mod_write(XAH_CTRL_0, CHB_MAX_CSMA_RETRIES << CHB_MAX_CSMA_RETIRES_POS, 0x7 << CHB_MAX_CSMA_RETIRES_POS); + //chb_reg_read_mod_write(CSMA_SEED_1, CHB_MIN_BE << CHB_MIN_BE_POS, 0x3 << CHB_MIN_BE_POS); + //chb_reg_read_mod_write(CSMA_SEED_1, CHB_CSMA_SEED1 << CHB_CSMA_SEED1_POS, 0x7 << CHB_CSMA_SEED1_POS); + //chb_ret_write(CSMA_SEED0, CHB_CSMA_SEED0); + //chb_reg_read_mod_write(PHY_CC_CCA, CHB_CCA_MODE << CHB_CCA_MODE_POS,0x3 << CHB_CCA_MODE_POS); + //chb_reg_write(CCA_THRES, CHB_CCA_ED_THRES); + //chb_reg_read_mod_write(PHY_TX_PWR, CHB_TX_PWR, 0xf); + + // set the channel + chb_set_channel(CHB_CHANNEL); + + // set autocrc mode + chb_reg_read_mod_write(PHY_TX_PWR, 1 << CHB_AUTO_CRC_POS, 1 << CHB_AUTO_CRC_POS); + + // set transceiver's fsm state + chb_set_state(RX_STATE); + + // set pan ID + chb_reg_write16(PAN_ID_0, CHB_PAN_ID); + + // set short addr + // NOTE: Possibly get this from EEPROM + chb_reg_write16(SHORT_ADDR_0, chb_get_short_addr()); + + // set long addr + // NOTE: Possibly get this from EEPROM + chb_get_ieee_addr(ieee_addr); + chb_reg_write64(IEEE_ADDR_0, ieee_addr); + + // do a read of the interrupt register to clear the interrupt bits + chb_reg_read(IRQ_STATUS); + + // re-enable intps while we config the radio + chb_reg_write(IRQ_MASK, 0x8); + + // enable mcu intp pin on INT6 for rising edge + CFG_CHB_INTP(); + + if (chb_get_state() != RX_STATE) + { + // ERROR occurred initializing the radio. Print out error message. + char buf[50]; + + // grab the error message from flash & print it out + strcpy_P(buf, chb_err_init); + Serial.print(buf); + } +} + +/**************************************************************************/ +/*! + Initialize the complete driver. +*/ +/**************************************************************************/ +void chb_drvr_init() +{ + // config SPI for at86rf230 access + chb_spi_init(); + + // configure IOs + CHB_SLPTR_DDIR |= (_BV(CHB_SLPTR_PIN)); + + // config radio + chb_radio_init(); +} + +/**************************************************************************/ +/*! + Enable or disable the radio's sleep mode. +*/ +/**************************************************************************/ +void chb_sleep(U8 enb) +{ + if (enb) + { + // first we need to go to TRX OFF state + chb_set_state(TRX_OFF); + + // then we need to make SLP_TR pin an input. this enables the external + // pullup on that pin. we do this so that we won't need to go through + // a voltage divider which drains current. we want to avoid that when + // we sleep + CHB_SLPTR_DDIR &= ~(_BV(CHB_SLPTR_PIN)); + } + else + { + // make sure the SLPTR pin is low first + CHB_SLPTR_PORT &= ~(_BV(CHB_SLPTR_PIN)); + + // make the SLPTR pin an output + CHB_SLPTR_DDIR |= _BV(CHB_SLPTR_PIN); + + // Turn the transceiver back on + chb_set_state(RX_STATE); + } +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_drvr.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_drvr.h new file mode 100644 index 0000000..449108e --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_drvr.h @@ -0,0 +1,242 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +#ifndef CHIBI_DRVR_H +#define CHIBI_DRVR_H + +#include +#include +#include "chibiUsrCfg.h" +#include "types.h" + +#define CHB_SPI_CMD_RW 0xC0 /**< Register Write (short mode). */ +#define CHB_SPI_CMD_RR 0x80 /**< Register Read (short mode). */ +#define CHB_SPI_CMD_FW 0x60 /**< Frame Transmit Mode (long mode). */ +#define CHB_SPI_CMD_FR 0x20 /**< Frame Receive Mode (long mode). */ +#define CHB_SPI_CMD_SW 0x40 /**< SRAM Write. */ +#define CHB_SPI_CMD_SR 0x00 /**< SRAM Read. */ +#define CHB_SPI_CMD_RADDRM 0x7F /**< Register Address Mask. */ + +#define CHB_IRQ_BAT_LOW_MASK 0x80 /**< Mask for the BAT_LOW interrupt. */ +#define CHB_IRQ_TRX_UR_MASK 0x40 /**< Mask for the TRX_UR interrupt. */ +#define CHB_IRQ_TRX_END_MASK 0x08 /**< Mask for the TRX_END interrupt. */ +#define CHB_IRQ_RX_START_MASK 0x04 /**< Mask for the RX_START interrupt. */ +#define CHB_IRQ_PLL_UNLOCK_MASK 0x02 /**< Mask for the PLL_UNLOCK interrupt. */ +#define CHB_IRQ_PLL_LOCK_MASK 0x01 /**< Mask for the PLL_LOCK interrupt. */ + +#define CHB_ENTER_CRIT() {U8 volatile saved_sreg = SREG; cli() +#define CHB_LEAVE_CRIT() SREG = saved_sreg;} + +#define CHB_SLPTR_ENABLE() do {CHB_SLPTR_PORT |= (_BV(CHB_SLPTR_PIN));} while (0) +#define CHB_SLPTR_DISABLE() do {CHB_SLPTR_PORT &= ~(_BV(CHB_SLPTR_PIN));} while (0) + +enum +{ + CCA_ED = 1, /**< Use energy detection above threshold mode. */ + CCA_CARRIER_SENSE = 2, /**< Use carrier sense mode. */ + CCA_CARRIER_SENSE_WITH_ED = 3 /**< Use a combination of both energy detection and carrier sense. */ +}; + +/**************************************************************************/ +/*! + This enumeration contains all the register addresses available in the + Atmel AT86RF230 radio. +*/ +/**************************************************************************/ +enum +{ + TRX_STATUS = 0x01, + TRX_STATE = 0x02, + TRX_CTRL0 = 0x03, + TRX_CTRL1 = 0x04, + PHY_TX_PWR = 0x05, + PHY_RSSI = 0x06, + PHY_ED_LEVEL = 0x07, + PHY_CC_CCA = 0x08, + CCA_THRES = 0x09, + IRQ_MASK = 0x0e, + IRQ_STATUS = 0x0f, + VREG_CTRL = 0x10, + BATMON = 0x11, + XOSC_CTRL = 0x12, + FTN_CTRL = 0x18, + PLL_CF = 0x1a, + PLL_DCU = 0x1b, + PART_NUM = 0x1c, + VERSION_NUM = 0x1d, + MAN_ID_0 = 0x1e, + MAN_ID_1 = 0x1f, + SHORT_ADDR_0 = 0x20, + SHORT_ADDR_1 = 0x21, + PAN_ID_0 = 0x22, + PAN_ID_1 = 0x23, + IEEE_ADDR_0 = 0x24, + IEEE_ADDR_1 = 0x25, + IEEE_ADDR_2 = 0x26, + IEEE_ADDR_3 = 0x27, + IEEE_ADDR_4 = 0x28, + IEEE_ADDR_5 = 0x29, + IEEE_ADDR_6 = 0x2a, + IEEE_ADDR_7 = 0x2b, + XAH_CTRL_0 = 0x2c, + CSMA_SEED_0 = 0x2d, + CSMA_SEED_1 = 0x2e +}; + +enum +{ + CHB_MAX_FRAME_RETRIES_POS = 4, + CHB_MAX_CSMA_RETIRES_POS = 1, + CHB_MIN_BE_POS = 6, + CHB_CSMA_SEED1_POS = 0, + CHB_CCA_MODE_POS = 5, + CHB_AUTO_CRC_POS = 7, + CHB_TRX_END_POS = 3, + CHB_TRAC_STATUS_POS = 5, + CHB_MIN_FRAME_LENGTH = 3, + CHB_MAX_FRAME_LENGTH = 0x7f +}; + +enum{ + TIME_TO_ENTER_P_ON = 510, /**< Transition time from VCC is applied to P_ON. */ + TIME_P_ON_TO_TRX_OFF = 510, /**< Transition time from P_ON to TRX_OFF. */ + TIME_SLEEP_TO_TRX_OFF = 880, /**< Transition time from SLEEP to TRX_OFF. */ + TIME_RESET = 6, /**< Time to hold the RST pin low during reset */ + TIME_ED_MEASUREMENT = 140, /**< Time it takes to do a ED measurement. */ + TIME_CCA = 140, /**< Time it takes to do a CCA. */ + TIME_PLL_LOCK = 150, /**< Maximum time it should take for the PLL to lock. */ + TIME_FTN_TUNING = 25, /**< Maximum time it should take to do the filter tuning. */ + TIME_NOCLK_TO_WAKE = 6, /**< Transition time from *_NOCLK to being awake. */ + TIME_CMD_FORCE_TRX_OFF = 1, /**< Time it takes to execute the FORCE_TRX_OFF command. */ + TIME_TRX_OFF_TO_PLL_ACTIVE = 180, /**< Transition time from TRX_OFF to: RX_ON, PLL_ON, TX_ARET_ON and RX_AACK_ON. */ + TIME_STATE_TRANSITION_PLL_ACTIVE = 1, /**< Transition time from PLL active state to another. */ +}; + +// These are the status codes that are used in this stack +enum{ + RADIO_SUCCESS = 0x40, /**< The requested service was performed successfully. */ + RADIO_UNSUPPORTED_DEVICE, /**< The connected device is not an Atmel AT86RF230. */ + RADIO_INVALID_ARGUMENT, /**< One or more of the supplied function arguments are invalid. */ + RADIO_TIMED_OUT, /**< The requested service timed out. */ + RADIO_WRONG_STATE, /**< The end-user tried to do an invalid state transition. */ + RADIO_BUSY_STATE, /**< The radio transceiver is busy receiving or transmitting. */ + RADIO_STATE_TRANSITION_FAILED, /**< The requested state transition could not be completed. */ + RADIO_CCA_IDLE, /**< Channel is clear, available to transmit a new frame. */ + RADIO_CCA_BUSY, /**< Channel busy. */ + RADIO_TRX_BUSY, /**< Transceiver is busy receiving or transmitting data. */ + RADIO_BAT_LOW, /**< Measured battery voltage is lower than voltage threshold. */ + RADIO_BAT_OK, /**< Measured battery voltage is above the voltage threshold. */ + RADIO_CRC_FAILED, /**< The CRC failed for the actual frame. */ + RADIO_CHANNEL_ACCESS_FAILURE, /**< The channel access failed during the auto mode. */ + RADIO_NO_ACK, /**< No acknowledge frame was received. */ +}; + +enum +{ + CMD_NOP = 0, + CMD_TX_START = 2, + CMD_FORCE_TRX_OFF = 3, + CMD_RX_ON = 6, + CMD_TRX_OFF = 8, + CMD_PLL_ON = 9, + CMD_RX_AACK_ON = 22, + CMD_TX_ARET_ON = 25 +}; + +enum +{ + P_ON = 0, + BUSY_RX = 1, + BUSY_TX = 2, + RX_ON = 6, + TRX_OFF = 8, + PLL_ON = 9, + SLEEP = 15, + BUSY_RX_AACK = 17, + BUSY_TX_ARET = 18, + RX_AACK_ON = 22, + TX_ARET_ON = 25, + RX_ON_NOCLK = 28, + RX_AACK_ON_NOCLK = 29, + BUSY_RX_AACK_NOCLK = 30 +}; + +/**************************************************************************/ +/*! + If promiscuous mode is enabled, then we don't want to use the extended + hardware features of the chip. We want raw frames that are unacknowledged. +*/ +/**************************************************************************/ +#if (CHIBI_PROMISCUOUS) + #define RX_STATE RX_ON +#else + #define RX_STATE RX_AACK_ON +#endif + +/**************************************************************************/ +/*! + Function Prototypes +*/ +/**************************************************************************/ +// init +void chb_drvr_init(); + +// data access +U8 chb_reg_read(U8 addr); +U16 chb_reg_read16(U8 addr); +void chb_reg_write(U8 addr, U8 val); +void chb_reg_write16(U8 addr, U16 val); +void chb_reg_write64(U8 addr, U8 *val); +void chb_reg_read_mod_write(U8 addr, U8 val, U8 mask); +void chb_frame_write(U8 *hdr, U8 hdr_len, U8 *data, U8 data_len); + +// general configuration +U8 chb_set_channel(U8 channel); +U8 chb_get_channel(); +void chb_set_ieee_addr(U8 *addr); +void chb_get_ieee_addr(U8 *addr); +void chb_set_short_addr(U16 addr); +U16 chb_get_short_addr(); +void chb_sleep(U8 enb); + +// data transmit +U8 chb_tx(U8 *hdr, U8 *data, U8 len); + +#ifdef CHB_DEBUG +// sram access +void chb_sram_read(U8 addr, U8 len, U8 *data); +void chb_sram_write(U8 addr, U8 len, U8 *data); +#endif + +#endif + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_eeprom.c b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_eeprom.c new file mode 100644 index 0000000..8c4fc9d --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_eeprom.c @@ -0,0 +1,63 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +/*! + \file + \ingroup + + +*/ +/**************************************************************************/ +#include "chb_eeprom.h" + +/**************************************************************************/ +/*! + +*/ +/**************************************************************************/ +void chb_eeprom_write(U16 addr, U8 *buf, U16 size) +{ + while(!eeprom_is_ready()); + eeprom_write_block(buf, (U16 *)addr, size); +} + +/**************************************************************************/ +/*! + +*/ +/**************************************************************************/ +void chb_eeprom_read(U16 addr, U8 *buf, U16 size) +{ + while(!eeprom_is_ready()); + eeprom_read_block(buf, (U16 *)addr, size); +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_eeprom.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_eeprom.h new file mode 100644 index 0000000..e8b7ef9 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_eeprom.h @@ -0,0 +1,51 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +/*! + \file + \ingroup + + +*/ +/**************************************************************************/ +#ifndef CHB_EEPROM_H +#define CHB_EEPROM_H + +#include +#include "chibiUsrCfg.h" +#include "types.h" + +void chb_eeprom_write(U16 addr, U8 *buf, U16 size); +void chb_eeprom_read(U16 addr, U8 *buf, U16 size); + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_rx_int.c b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_rx_int.c new file mode 100644 index 0000000..f3ccecc --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_rx_int.c @@ -0,0 +1,136 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +/*! + \file + \ingroup + + +*/ +/**************************************************************************/ +#include "WProgram.h" +#include "chb.h" +#include "chb_drvr.h" +#include "chb_spi.h" + +/**************************************************************************/ +/*! + This the main ISR for the Chibi radio stack. It doesn't use a standard + IRQ pin. Instead it uses a general purpose IO configured as an edge-detecting + interrupt pin. That means that this interrupt needs to qualify the pin + as a positive rising edge before executing the actual service routine. +*/ +/**************************************************************************/ +ISR(CHB_RADIO_IRQ) +{ + U8 dummy, state, pinval, intp_src = 0; + pcb_t *pcb = chb_get_pcb(); + + CHB_ENTER_CRIT(); + + // get the pin's value to check whether it was a rising or falling edge. + pinval = PINB & _BV(PINB6); + + // we'll only enter the ISR if the interrupt is a positive edge. + if (pinval) + { + /*Read Interrupt source.*/ + CHB_SPI_ENABLE(); + + /*Send Register address and read register content.*/ + dummy = chb_xfer_byte(IRQ_STATUS | CHB_SPI_CMD_RR); + intp_src = chb_xfer_byte(0); + + CHB_SPI_DISABLE(); + + while (intp_src) + { + /*Handle the incomming interrupt. Prioritized.*/ + if ((intp_src & CHB_IRQ_RX_START_MASK)) + { + intp_src &= ~CHB_IRQ_RX_START_MASK; + } + else if (intp_src & CHB_IRQ_TRX_END_MASK) + { + state = chb_get_state(); + + if ((state == RX_ON) || (state == RX_AACK_ON) || (state == BUSY_RX_AACK)) + { + // get the ed measurement + pcb->ed = chb_reg_read(PHY_ED_LEVEL); + + // get the crc + pcb->crc = (chb_reg_read(PHY_RSSI) & (1<<7)) ? 1 : 0; + + // if the crc is not valid, then do not read the frame and set the rx flag + if (pcb->crc) + { + // get the data + chb_frame_read(); + pcb->rcvd_xfers++; + pcb->data_rcv = true; + } + } + else + { + pcb->tx_end = true; + } + intp_src &= ~CHB_IRQ_TRX_END_MASK; + while (chb_set_state(RX_STATE) != RADIO_SUCCESS); + } + else if (intp_src & CHB_IRQ_TRX_UR_MASK) + { + intp_src &= ~CHB_IRQ_TRX_UR_MASK; + pcb->underrun++; + } + else if (intp_src & CHB_IRQ_PLL_UNLOCK_MASK) + { + intp_src &= ~CHB_IRQ_PLL_UNLOCK_MASK; + } + else if (intp_src & CHB_IRQ_PLL_LOCK_MASK) + { + intp_src &= ~CHB_IRQ_PLL_LOCK_MASK; + } + else if (intp_src & CHB_IRQ_BAT_LOW_MASK) + { + intp_src &= ~CHB_IRQ_BAT_LOW_MASK; + pcb->battlow++; + } + else + { + } + } + } + + CHB_LEAVE_CRIT(); +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_rx_int.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_rx_int.h new file mode 100644 index 0000000..38f0cc6 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_rx_int.h @@ -0,0 +1,49 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +/*! + \file + \ingroup + + +*/ +/**************************************************************************/ +#ifndef CHB_RX_LOW_LAT_H +#define CHB_RX_LOW_LAT_H + +#include +#include +#include "chibiUsrCfg.h" +#include "types.h" + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_rx_poll.c b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_rx_poll.c new file mode 100644 index 0000000..bb6e628 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_rx_poll.c @@ -0,0 +1,187 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +/*! + \file + \ingroup + + +*/ +/**************************************************************************/ +#include "WProgram.h" +#include "chb.h" +#include "chb_drvr.h" +#include "chb_spi.h" + +static U8 intp_src = 0; +static bool rx_intp_flag = false; + +/**************************************************************************/ +/*! + This is the main IRQ handler for chibi. It's not in an actual ISR and is + only called after an interrupt occurs. +*/ +/**************************************************************************/ +static void chb_irq_handler() +{ + U8 dummy, state, pinval; + pcb_t *pcb = chb_get_pcb(); + + // find out who issued the interrupt + intp_src |= chb_reg_read(IRQ_STATUS); + + while (intp_src) + { + /*Handle the incomming interrupt. Prioritized.*/ + if ((intp_src & CHB_IRQ_RX_START_MASK)) + { + intp_src &= ~CHB_IRQ_RX_START_MASK; + } + else if (intp_src & CHB_IRQ_TRX_END_MASK) + { + state = chb_get_state(); + if ((state == RX_ON) || (state == RX_AACK_ON) || (state == BUSY_RX_AACK)) + { + // get the ed measurement + pcb->ed = chb_reg_read(PHY_ED_LEVEL); + + // get the crc + pcb->crc = (chb_reg_read(PHY_RSSI) & (1<<7)) ? 1 : 0; + + // if the crc is not valid, then do not read the frame and set the rx flag + if (pcb->crc) + { + pcb->data_rcv = true; + chb_frame_read(); // get the data + pcb->rcvd_xfers++; + } + } + + intp_src &= ~CHB_IRQ_TRX_END_MASK; + while (chb_set_state(RX_STATE) != RADIO_SUCCESS); + } + else if (intp_src & CHB_IRQ_TRX_UR_MASK) + { + intp_src &= ~CHB_IRQ_TRX_UR_MASK; + pcb->underrun++; + } + else if (intp_src & CHB_IRQ_PLL_UNLOCK_MASK) + { + intp_src &= ~CHB_IRQ_PLL_UNLOCK_MASK; + } + else if (intp_src & CHB_IRQ_PLL_LOCK_MASK) + { + intp_src &= ~CHB_IRQ_PLL_LOCK_MASK; + } + else if (intp_src & CHB_IRQ_BAT_LOW_MASK) + { + intp_src &= ~CHB_IRQ_BAT_LOW_MASK; + pcb->battlow++; + } + else + { + } + } + rx_intp_flag = false; + CHB_IRQ_ENABLE(); +} + +/**************************************************************************/ +/*! + This is the function that checks to see if any interrupt occurred. If it + did, then it will execute the handler and return a flag indicating + new data is available. +*/ +/**************************************************************************/ +void chb_rcv_poll() +{ + pcb_t *pcb = chb_get_pcb(); + + // if an interrupt occured, handle it + if (rx_intp_flag) + { + chb_irq_handler(); + } +} + + +/**************************************************************************/ +/*! + This the main ISR for the Chibi radio stack. It doesn't use a standard + IRQ pin. Instead it uses a general purpose IO configured as an edge-detecting + interrupt pin. That means that this interrupt needs to qualify the pin + as a positive rising edge before executing the actual service routine. +*/ +/**************************************************************************/ +ISR(CHB_RADIO_IRQ) +{ + pcb_t *pcb = chb_get_pcb(); + U8 state, pinval; + + CHB_ENTER_CRIT(); + + // check if the pin is high or low which indicates rising or falling edge + // interrupt + pinval = PINB & _BV(PINB6); + + // if it was a rising edge, then flag it as a real interrupt + if (pinval) + { + // we can only access the SPI if we're transmitting. That's because + // we're in full control of the SPI bus. Otherwise, the ethernet shield + // has a bug that blocks other SPI devices when its using it. + if (pcb->tx_busy) + { + // get the interrupt source + intp_src |= chb_reg_read(IRQ_STATUS); + + if (intp_src && CHB_IRQ_TRX_END_MASK) + { + // if we're transmitting, then signal the end of the transmission + pcb->tx_end = true; + pcb->tx_busy = false; + intp_src &= ~CHB_IRQ_TRX_END_MASK; + while (chb_set_state(RX_STATE) != RADIO_SUCCESS); + + // we're finished here + return; + } + } + + // if its a receive interrupt, then disable the IRQ on the MCU side. + // we'll flag the interrupt and process it later outside of the isr + rx_intp_flag = true; + CHB_IRQ_DISABLE(); + } + CHB_LEAVE_CRIT(); +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_rx_poll.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_rx_poll.h new file mode 100644 index 0000000..d2728c6 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_rx_poll.h @@ -0,0 +1,51 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +/*! + \file + \ingroup + + +*/ +/**************************************************************************/ +#ifndef CHB_RX_H +#define CHB_RX_H + +#include +#include +#include "chibiUsrCfg.h" +#include "types.h" + +void chb_rcv_poll(); + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_spi.c b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_spi.c new file mode 100644 index 0000000..92994fe --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/chb_spi.c @@ -0,0 +1,90 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. + +*******************************************************************/ +/*! + \file + \ingroup + + +*/ +/**************************************************************************/ +#include "chb.h" +#include "chb_spi.h" + +/**************************************************************************/ +/*! + Initialize the SPI +*/ +/**************************************************************************/ +void chb_spi_init() +{ + // configure the SPI slave_select, spi clk, and mosi pins as output. the miso pin + // is cleared since its an input. + CHB_SPI_DDIR |= _BV(CHB_SCK) | _BV(CHB_MOSI); + CHB_SPI_CS_DDIR |= _BV(CHB_SPI_CS_PIN); + + CHB_SPI_PORT |= _BV(CHB_SCK); + CHB_SPI_CS_PORT |= _BV(CHB_SPI_CS_PIN); + + // enable pullups on MISO to make the rise times faster + CHB_SPI_PORT |= _BV(CHB_MISO); + + // *IMPORTANT* enable the pullup on the original SPI CS pin. Otherwise, if it suddenly goes low, + // the SPI will default to slave mode. + CHB_SPI_PORT |= _BV(CHB_SPI_SELN); + + // set to master mode + // set the clock freq + SPCR |= _BV(MSTR) | _BV(SPR0); + SPSR |= _BV(SPI2X); + + // enable the SPI master + SPCR |= (1 << SPE); + + // set the slave select to idle + CHB_SPI_DISABLE(); +} + +/**************************************************************************/ +/*! + This function both reads and writes data. For write operations, include data + to be written as argument. For read ops, use dummy data as arg. Returned + data is read byte val. +*/ +/**************************************************************************/ +U8 chb_xfer_byte(U8 data) +{ + SPDR = data; + while (!(SPSR & (1< +#include "chibiUsrCfg.h" + +#define CHB_SPI_ENABLE() do {CHB_SPI_CS_PORT &= ~(_BV(CHB_SPI_CS_PIN));} while (0) +#define CHB_SPI_DISABLE() do {CHB_SPI_CS_PORT |= _BV(CHB_SPI_CS_PIN);} while (0) + +/* Note: The SPI chip select pin is defined in chibiUsrCfg.h */ +#define CHB_SPI_PORT PORTB +#define CHB_SPI_DDIR DDRB +#define CHB_SCK 5 // PB.5 - Output: SPI Serial Clock (SCLK) +#define CHB_MOSI 3 // PB.3 - Output: SPI Master out - slave in (MOSI) +#define CHB_MISO 4 // PB.4 - Input: SPI Master in - slave out (MISO) +#define CHB_SPI_SELN 2 // PB.2 - Input: The dedicated SPI CS pin needs to have internal pullup enabled if an input + +void chb_spi_init(); +U8 chb_xfer_byte(U8 data); + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/types.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/types.h new file mode 100644 index 0000000..c551bbc --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/FreakDuino_Chibi/src/types.h @@ -0,0 +1,54 @@ +/******************************************************************* + Copyright (C) 2009 FreakLabs + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Originally written by Christopher Wang aka Akiba. + Please post support questions to the FreakLabs forum. +*******************************************************************/ +/*! + \file types.h + \ingroup usb +*/ +/*******************************************************************/ +#ifndef TYPES_H +#define TYPES_H + +#include +#include + +// Standard data types +typedef uint8_t U8; /// Generic 8 bit unsigned data type +typedef uint16_t U16; /// Generic 16 bit unsigned data type +typedef uint32_t U32; /// Generic 32 bit unsigned data type +typedef uint64_t U64; /// Generic 64 bit unsigned data type + +typedef int8_t S8; /// Generic 8 bit signed data type +typedef int16_t S16; /// Generic 16 bit signed data type +typedef int32_t S32; /// Generic 32 bit signed data type + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/RX8025/RX8025.cpp b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/RX8025/RX8025.cpp new file mode 100644 index 0000000..b93380f --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/RX8025/RX8025.cpp @@ -0,0 +1,80 @@ +#include +#include "RX8025.h" +//******************************************************************** + +//=============================================== +#define RX8025_address 0x32 + +unsigned char RX8025_Control[2]= +{ + 0x20,0x00 +}; + +//=============================================== +void setRtcTime(void) +{ + Wire.beginTransmission(RX8025_address); + Wire.send(0x00); + for(unsigned char i=0; i<7; i++) + { + Wire.send(RX8025_time[i]); + } + Wire.endTransmission(); +} + +//=============================================== +uint8_t bcd2bin (uint8_t val) +{ + return val - 6 * (val >> 4); +} + +uint8_t bin2bcd (uint8_t val) +{ + return val + 6 * (val / 10); +} + +//=============================================== +void getRtcTime(void) +{ + unsigned char i=0; + Wire.beginTransmission(RX8025_address); + Wire.send(0x00); + Wire.endTransmission();// + Wire.requestFrom(RX8025_address,8); + RX8025_time[i]= Wire.receive();//not use + while(Wire.available()) + { + RX8025_time[i]= Wire.receive(); + i++; + } + Wire.endTransmission();// + + year = bcd2bin(RX8025_time[6]&0xff); + month = bcd2bin(RX8025_time[5]&0x1f); + date = bcd2bin(RX8025_time[4]&0x3f); + week = bcd2bin(RX8025_time[3]&0x07); + hour = bcd2bin(RX8025_time[2]&0x3f); + minute = bcd2bin(RX8025_time[1]&0x7f); + second = bcd2bin(RX8025_time[0]&0x7f); +} + +//=============================================== +void RX8025_init(void) +{ + Wire.begin(); + Wire.beginTransmission(RX8025_address);//clear power on reset flag, set to 24hr format + Wire.send(0xe0); + for(unsigned char i=0; i<2; i++) + { + Wire.send(RX8025_Control[i]); + } + Wire.endTransmission(); + //setRtcTime(); +} + + + + + + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/RX8025/RX8025.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/RX8025/RX8025.h new file mode 100644 index 0000000..ad4523c --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/RX8025/RX8025.h @@ -0,0 +1,35 @@ +#ifndef RX8025_h +#define RX8025_h + +#define RX8025_SEC 0 +#define RX8025_MIN 1 +#define RX8025_HR 2 +#define RX8025_WEEK 3 +#define RX8025_DATE 4 +#define RX8025_MTH 5 +#define RX8025_YR 6 +#define RX8025_Doffset 7 +#define RX8025_AW_MIN 8 +#define RX8025_AW_HR 9 +#define RX8025_AW_WEEK 10 +#define RX8025_AD_MIN 11 +#define RX8025_AD_HR 12 +#define RX8025_CTL1 14 +#define RX8025_CTL2 15 + +extern unsigned char RX8025_time[7]; + +extern unsigned char hour; +extern unsigned char minute; +extern unsigned char second; +extern unsigned char week; +extern unsigned char year; +extern unsigned char month; +extern unsigned char date; + + +void RX8025_init(void); +void getRtcTime(void); +void setRtcTime(void); + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/TF library Readme.txt b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/TF library Readme.txt new file mode 100644 index 0000000..ba12171 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/TF library Readme.txt @@ -0,0 +1,6 @@ +The TF library is for the Stalker board. +It preformats data messages to be written to the CF card. + +To format your own messages: +1: copy the library and rename it. +2: edit to suit your project. \ No newline at end of file diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/TF/TF.cpp b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/TF/TF.cpp new file mode 100644 index 0000000..558ab76 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/TF/TF.cpp @@ -0,0 +1,182 @@ +#include "TF.h" + +//********************************** + + +SdCard card; +Fat16 file; + +// store error strings in flash to save RAM +#define error(s) error_P(PSTR(s)) + +void error_P(const char* str) +{ + PgmPrint("error: "); + SerialPrintln_P(str); + if (card.errorCode) + { + PgmPrint("SD error: "); + Serial.println(card.errorCode, HEX); + } + Serial.println("TF error"); +} + +void TF_card_init(void) +{ + //Serial.println(); + pinMode(SD_power_IO,INPUT);//extern power + //pinMode(SD_power_IO,OUTPUT); + //digitalWrite(SD_power_IO,HIGH);//power up SD card + //delay(10); + //PgmPrintln("Type any character to start"); + + // initialize the SD card + if (!card.init()) error("card.init"); + + // initialize a FAT16 volume + if (!Fat16::init(&card)) error("Fat16::init"); + // clear write error + file.writeError = false; +} + +//======================================= +void store_tmp102_data(void) +{ + file.print("tep102_temperature = "); + file.println(convertedtemp); +} + +//======================================== +void store_Battery_data(void) +{ + switch (charge_status) + { + case 0x01: + { + file.print("CH_sleeping"); + break; + } + case 0x02: + { + file.print("CH_complete"); + break; + } + case 0x04: + { + file.print("CH_charging"); + break; + } + case 0x08: + { + file.print("CH_bat_not_exist"); + break; + } + } + file.print(" battery voltage = "); + file.println(bat_voltage); +} + +//============================= +void store_RTC_time(void) +{ + /* unsigned char RX8025_time[7]= + { + 0x15,0x44,0x14,0x03,0x03,0x11,0x10 //second, minute, hour, week, date, month, year, BCD format + }; + */ + + file.print(year,DEC); + file.print("/"); + file.print(month,DEC); + file.print("/"); + file.print(date,DEC); + switch(week) + { + case 0x00: + { + file.print("/Sunday "); + break; + } + case 0x01: + { + file.print("/Monday "); + break; + } + case 0x02: + { + file.print("/Tuesday "); + break; + } + case 0x03: + { + file.print("/Wednesday "); + break; + } + case 0x04: + { + file.print("/Thursday "); + break; + } + case 0x05: + { + file.print("/Friday "); + break; + } + case 0x06: + { + file.print("/Saturday "); + break; + } + } + file.print(hour,DEC); + file.print(":"); + file.print(minute,DEC); + file.print(":"); + file.println(second,DEC); +} + +//====================================== +void write_data_to_TF(void) +{ + // O_CREAT - create the file if it does not exist + // O_APPEND - seek to the end of the file prior to each write + // O_WRITE - open for write + if (!file.open(name, O_CREAT | O_APPEND | O_WRITE)) + { + error("open"); + } + + + store_RTC_time(); + store_tmp102_data(); + store_Battery_data(); + + file.println("--------------next--data---------------"); + file.println(); + + if (file.writeError) + { + error("write"); + } + if (!file.close()) + { + error("close"); + } +} + + + + + + + + + + + + + + + + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/TF/TF.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/TF/TF.h new file mode 100644 index 0000000..ae194c0 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/TF/TF.h @@ -0,0 +1,40 @@ +#ifndef TF_h +#define TF_h + +//********************************************** +/* + * Append Example + * + * This sketch shows how to use open for append and the Arduino Print class + * with Fat16. + */ +#include +#include // use functions to print strings from flash memory + + +#define SD_power_IO 4 + +//============================================== +extern char name[];//file name in TF card root dir + +extern float convertedtemp; +extern int tmp102_val; + +extern float bat_voltage; +extern unsigned int bat_read; +extern unsigned char charge_status; + +extern unsigned char hour; +extern unsigned char minute; +extern unsigned char second; +extern unsigned char week; +extern unsigned char year; +extern unsigned char month; +extern unsigned char date; +extern unsigned char RX8025_time[7]; +//============================================== +void TF_card_init(void); +void write_data_to_TF(void); +//********************************************** + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/battery/Battery.cpp b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/battery/Battery.cpp new file mode 100644 index 0000000..e1a86bb --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/battery/Battery.cpp @@ -0,0 +1,84 @@ +#include "Battery.h" +#include + +//********************************** +/* +void Battery_init(void) + init Battery IOs and ADC7 + */ +void Battery_init(void) +{ + analogReference(INTERNAL);//internal 1.1v in Atmega328 + pinMode(CH_Status,INPUT); + pinMode(OK_Status,INPUT); + digitalWrite(CH_Status,HIGH);//pull high + digitalWrite(OK_Status,HIGH);//pull high + Battery_charge_status(); + Battery_voltage_read(); +} + +//==================================== +void Battery_charge_status(void) +{ + boolean OK = digitalRead(OK_Status); + boolean CH = digitalRead(CH_Status); + if(OK&&CH)//Charger is sleeping, will auto start charge battery when FB voltage less than 3.0v + { + charge_status = 0x01; + } + + else if(CH)//Charge complete + { + charge_status = 0x02; + } + + else if(OK)//Charging + { + charge_status = 0x04; + } + + else//USB power exsit, battery is not exist + { + charge_status = 0x08; + //Serial.println("Bad Battery or Battery is not exist"); + } +} + +//===================================== +void Battery_voltage_read(void) +{ + bat_read = analogRead(BAT_voltage); + + // (1/1024)*6=0.0064453125, + bat_voltage = (float)bat_read * 0.0064453125; + + //Serial.print(" -->Battery data = "); + //Serial.println(bat_read); + + if(bat_read<570)// less than 3.48v + { + Serial.println("low battery, please recharge"); + } + else if(bat_read>680)// more than 4.22 v + { + Serial.println("out of range, over charge?"); + } + else + { + // battery is fine + } +} + + + + + + + + + + + + + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/battery/Battery.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/battery/Battery.h new file mode 100644 index 0000000..c121f99 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/battery/Battery.h @@ -0,0 +1,19 @@ +#ifndef Battery_h +#define Battery_h + +//********************************************** +#define CH_Status 6 +#define OK_Status 7 +#define BAT_voltage 7 +//============================================== +extern unsigned int bat_read; +extern float bat_voltage; +extern unsigned char charge_status; + +//============================================== +void Battery_init(void); +void Battery_voltage_read(void); +void Battery_charge_status(void); +//********************************************** + +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/myRX8025.zip b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/myRX8025.zip new file mode 100644 index 0000000..b1d2b1d Binary files /dev/null and b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/myRX8025.zip differ diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/myRX8025/myRX8025.cpp b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/myRX8025/myRX8025.cpp new file mode 100644 index 0000000..9d2bb58 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/myRX8025/myRX8025.cpp @@ -0,0 +1,139 @@ +#include +#include "myRX8025.h" + +//=============================================== +#define RX8025_address 0x32 + +//=============================================== +uint8_t bcd2bin (uint8_t val) +{ + return val - 6 * (val >> 4); +} + +uint8_t bin2bcd (uint8_t val) +{ + return val + 6 * (val / 10); +} + +//=============================================== +void RX8025_init(void) +{ + setRtcCtrl(); + setRtcTime(); +} + +//=============================================== +void setRtcTime(void) +{ + Wire.beginTransmission(RX8025_address); + Wire.send(0x00); + for(unsigned char i=0; i<7; i++) + { + Wire.send(RX8025_time[i]); + } + Wire.endTransmission(); +} + +//=============================================== +void getRtcTime(void) +{ + unsigned char i=0; + Wire.beginTransmission(RX8025_address); + Wire.send(0x00); + Wire.endTransmission();// + Wire.requestFrom(RX8025_address,8); + RX8025_time[i]= Wire.receive();//not use + while(Wire.available()) + { + RX8025_time[i]= Wire.receive(); + i++; + } + Wire.endTransmission();// + + year = bcd2bin(RX8025_time[6]&0xff); + month = bcd2bin(RX8025_time[5]&0x1f); + day = bcd2bin(RX8025_time[4]&0x3f); + weekday = bcd2bin(RX8025_time[3]&0x07); + hour = bcd2bin(RX8025_time[2]&0x3f); + minute = bcd2bin(RX8025_time[1]&0x7f); + second = bcd2bin(RX8025_time[0]&0x7f); +} + +//=============================================== +void getRtcAll(void) +{ + unsigned char i=0; + unsigned char RX8025_all[16]; + Wire.beginTransmission(RX8025_address); + Wire.send(0x00); + Wire.endTransmission();// + Wire.requestFrom(RX8025_address,16); + RX8025_all[i]= Wire.receive();//not use + while(Wire.available()) + { + RX8025_all[i]= Wire.receive(); + i++; + } + Wire.endTransmission(); + RX8025_control_2 = bcd2bin(RX8025_all[15]); + RX8025_control_1 = bcd2bin(RX8025_all[14]); + RX8025_Reserved = bcd2bin(RX8025_all[13]); + alarmD_hour = bcd2bin(RX8025_all[12]&0x3f); + alarmD_minute = bcd2bin(RX8025_all[11]&0x7f); + alarmW_weekday = bcd2bin(RX8025_all[10]&0x07); + alarmW_hour = bcd2bin(RX8025_all[9]&0x3f); + alarmW_minute = bcd2bin(RX8025_all[8]&0x7f); + Doffset = bcd2bin(RX8025_all[7]); + year = bcd2bin(RX8025_all[6]&0xff); + month = bcd2bin(RX8025_all[5]&0x1f); + day = bcd2bin(RX8025_all[4]&0x3f); + weekday = bcd2bin(RX8025_all[3]&0x07); + hour = bcd2bin(RX8025_all[2]&0x3f); + minute = bcd2bin(RX8025_all[1]&0x7f); + second = bcd2bin(RX8025_all[0]&0x7f); +} + +//=============================================== +void setRtcAlarmD(void) +{ + Wire.beginTransmission(RX8025_address); + Wire.send(0xB0); + for(unsigned char i=0; i<2; i++) + { + Wire.send(RX8025_alarmD[i]); + } + Wire.endTransmission(); +} + +//=============================================== +void setRtcAlarmW(void) +{ + Wire.beginTransmission(RX8025_address); + Wire.send(0x80); + for(unsigned char i=0; i<3; i++) + { + Wire.send(RX8025_alarmW[i]); + } + Wire.endTransmission(); +} + +//=============================================== +void setRtcCtrl(void) +{ +Wire.beginTransmission(RX8025_address); + Wire.send(0xE0); + for(unsigned char i=0; i<2; i++) + { + Wire.send(RX8025_Control[i]); + } + Wire.endTransmission(); +} + +//=============================================== +void RtcClearFlags(void) +{ + Wire.beginTransmission(RX8025_address); + Wire.send(0xF0); + Wire.send(RX8025_Control[1]); + Wire.endTransmission(); +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/myRX8025/myRX8025.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/myRX8025/myRX8025.h new file mode 100644 index 0000000..3f69075 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/myRX8025/myRX8025.h @@ -0,0 +1,58 @@ +#ifndef myRX8025_h +#define myRX8025_h + +//================================================= +#define RX8025_SEC 0 +#define RX8025_MIN 1 +#define RX8025_HR 2 +#define RX8025_WEEK 3 +#define RX8025_DATE 4 +#define RX8025_MTH 5 +#define RX8025_YR 6 +#define RX8025_Doffset 7 +#define RX8025_AW_MIN 8 +#define RX8025_AW_HR 9 +#define RX8025_AW_WEEK 10 // A +#define RX8025_AD_MIN 11 // B +#define RX8025_AD_HR 12 // C +#define RX8025_AD_RES 13 // D Reserved! DONT OVERWRITE! +#define RX8025_CTL1 14 // E +#define RX8025_CTL2 15 // F + +//================================================= +extern unsigned char second; // 0 +extern unsigned char minute; // 1 +extern unsigned char hour; // 2 +extern unsigned char weekday; // 3 +extern unsigned char day; // 4 +extern unsigned char month; // 5 +extern unsigned char year; // 6 +extern unsigned char Doffset; // 7 +extern unsigned char alarmW_minute; // 8 +extern unsigned char alarmW_hour; // 9 +extern unsigned char alarmW_weekday; // 10 A +extern unsigned char alarmD_minute; // 11 B +extern unsigned char alarmD_hour; // 12 C +extern unsigned char RX8025_Reserved; // 13 D Leave it alone! +extern unsigned char RX8025_control_1;// 14 E +extern unsigned char RX8025_control_2;// 15 F + +//================================================= +extern unsigned char RX8025_all[16]; +extern unsigned char RX8025_time[7]; +extern unsigned char RX8025_alarmW[3]; +extern unsigned char RX8025_alarmD[2]; +extern unsigned char RX8025_Control[2]; + +//================================================= +void RX8025_init(void); +void setRtcTime(void); +void getRtcTime(void); +void getRtcAll(void); +void setRtcAlarmW(void); +void setRtcAlarmD(void); +void setRtcCtrl(void); +void RtcClearFlags(void); + +//================================================= +#endif diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/tmp102/tmp102.cpp b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/tmp102/tmp102.cpp new file mode 100644 index 0000000..d2aae39 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/tmp102/tmp102.cpp @@ -0,0 +1,71 @@ +#include "tmp102.h" + +//********************************** +void tmp102_init(void) +{ + Wire.begin(); // start the I2C library +} + + +void getTemp102(void) +{ + unsigned char firstbyte; + unsigned char secondbyte; //these are the bytes we read from the TMP102 temperature registers + unsigned int complement;// = 0xe70 - 1 + + //float correctedtemp; + // The sensor overreads (?) + + /* Reset the register pointer (by default it is ready to read temperatures) + You can alter it to a writeable register and alter some of the configuration - + the sensor is capable of alerting you if the temperature is above or below a specified threshold. */ + + Wire.beginTransmission(TMP102_I2C_ADDRESS); //Say hi to the sensor. + Wire.send(0x00); + Wire.endTransmission(); + Wire.requestFrom(TMP102_I2C_ADDRESS, 2); + Wire.endTransmission(); + + firstbyte = (Wire.receive()); + /*read the TMP102 datasheet - here we read one byte from + each of the temperature registers on the TMP102*/ + secondbyte = (Wire.receive()); + /*The first byte contains the most significant bits, and + the second the less significant */ + tmp102_val = ((firstbyte) << 4); + /* MSB */ + tmp102_val |= (secondbyte >> 4); + /* LSB is ORed into the second 4 bits of our byte. + Bitwise maths is a bit funky, but there's a good tutorial on the playground*/ + + /* + + Serial.println(); + Serial.print("complement1 = 0x"); + Serial.println(complement,HEX); + + complement ^= 0xfff; + + Serial.println(); + Serial.print("complement2 = 0x"); + Serial.println(complement,HEX); + */ + + if(tmp102_val&0x800)//negative temperature + { + complement = tmp102_val - 1; + complement ^= 0xfff; + convertedtemp = complement * 0.0625 * (-1); + } + else + { + convertedtemp = tmp102_val * 0.0625; + } + //correctedtemp = convertedtemp - 5; + /* See the above note on overreading */ +} + + + + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/tmp102/tmp102.h b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/tmp102/tmp102.h new file mode 100644 index 0000000..0bd56c9 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch04 Tele-Sensation/libraries/tmp102/tmp102.h @@ -0,0 +1,33 @@ +#ifndef tmp102_h +#define tmp102_h + +//********************************************** +#include +#include +#define TMP102_I2C_ADDRESS 72 /* This is the I2C address for our chip. +This value is correct if you tie the ADD0 pin to ground. See the datasheet for some other values. */ + +/* + Table 1. Pointer Register Byte + P7 P6 P5 P4 P3 P2 P1 P0 + 0 0 0 0 0 0 Register Bits + + P1 P0 REGISTER + 0 0 Temperature Register (Read Only) + 0 1 Configuration Register (Read/Write) + 1 0 T LOW Register (Read/Write) + 1 1 T HIGH Register (Read/Write) + */ + +//============================================== +extern float convertedtemp; +extern int tmp102_val; +//============================================== +void tmp102_init(void); +void getTemp102(void); +//********************************************** + +#endif + + + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch05 Contributing to the Hive mind (Pachube)/CH5_1_modified_firmata/CH5_1_modified_firmata.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch05 Contributing to the Hive mind (Pachube)/CH5_1_modified_firmata/CH5_1_modified_firmata.pde new file mode 100644 index 0000000..91612fe --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch05 Contributing to the Hive mind (Pachube)/CH5_1_modified_firmata/CH5_1_modified_firmata.pde @@ -0,0 +1,81 @@ +/* + * This firmware reads all inputs and sends them as fast as it can. It was + * inspired by the ease-of-use of the Arduino2Max program. + * + * This example code is in the public domain. + * + * Note: one bug fix and changed sampling interval / com speed EWP + */ +#include + +byte pin; + +int analogValue; +int previousAnalogValues[TOTAL_ANALOG_PINS]; + +byte portStatus[TOTAL_PORTS]; // each bit: 1=pin is digital input, 0=other/ignore +byte previousPINs[TOTAL_PORTS]; + +/* timer variables */ +unsigned long currentMillis; // store the current value from millis() +unsigned long previousMillis; // for comparison with currentMillis +/* make sure that the FTDI buffer doesn't go over 60 bytes, otherwise you + get long, random delays. So only read analogs every 20ms or so */ +int samplingInterval = 1000; // how often to run the main loop (in ms) + +void sendPort(byte portNumber, byte portValue) +{ + portValue = portValue & portStatus[portNumber]; + if(previousPINs[portNumber] != portValue) { + Firmata.sendDigitalPort(portNumber, portValue); + previousPINs[portNumber] = portValue; + } +} + +void setup() +{ + byte i, port, status; + + Firmata.setFirmwareVersion(0, 1); + + for(pin = 0; pin < TOTAL_PINS; pin++) { + if IS_PIN_DIGITAL(pin) pinMode(PIN_TO_DIGITAL(pin), INPUT); + } + + for (port=0; port samplingInterval) { + previousMillis += samplingInterval; + while(Firmata.available()) { + Firmata.processInput(); + } + for(pin = 0; pin < TOTAL_ANALOG_PINS; pin++) { + analogValue = analogRead(pin); + if(analogValue != previousAnalogValues[pin]) { + Firmata.sendAnalog(pin, analogValue); + previousAnalogValues[pin] = analogValue; + } + } + } +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch05 Contributing to the Hive mind (Pachube)/CH5_2_Processing_firmata_pachube_logger/CH5_2_Processing_firmata_pachube_logger.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch05 Contributing to the Hive mind (Pachube)/CH5_2_Processing_firmata_pachube_logger/CH5_2_Processing_firmata_pachube_logger.pde new file mode 100644 index 0000000..1dd0068 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch05 Contributing to the Hive mind (Pachube)/CH5_2_Processing_firmata_pachube_logger/CH5_2_Processing_firmata_pachube_logger.pde @@ -0,0 +1,74 @@ +import processing.serial.*; +import cc.arduino.*; +import eeml.*; + +Arduino arduino1; +float lastUpdate; + +int Analog0, Analog1, Analog2, Analog3, Analog4; + +DataOut dOut1; + + +int TSensor = 4; // temperature sensor ADC input pin +int TempADC = 0; // variable to store ADC value read +int TempOffset = 500; // value in mV when ambient is 0 degrees C +int TempCoef = 10; // Temperature coefficient mV per Degree C +float ADCmV = 4.88; // mV per ADC increment (5 volts / 1024 increments) +float TempCalc = 0; // calculated temperature in C (accuraccy to two decimal places) + + + +void setup() +{ + // establish connection to the Arduino + println(Arduino.list()); + arduino1 = new Arduino(this, Arduino.list()[2], 28800); + + dOut1 = new DataOut(this, "http://www.pachube.com/api/[your feed number here].xml", "[ your api key here ]"); + +// notify Pachube of the Stream ID and Stream TAGs + dOut1.addData(0, "Analog 0, knob 1"); // add one line for each stream + dOut1.addData(1, "Analog 1, knob 2"); // the Stream ID in the stream number plus tags + dOut1.addData(2, "Analog 2, knob 3"); + dOut1.addData(3, "Analog 3, knob 4"); + dOut1.addData(4, "Analog 4, temperature sensor, MCP9700"); +} + +void draw() +{ + // update once every 12 seconds (could also be e.g. every mouseClick) + if ((millis() - lastUpdate) > 12000){ + println("ready to POST: "); + // Read Arduino1’s analog ports: + Analog0 = arduino1.analogRead(0); + Analog1 = arduino1.analogRead(1); + Analog2 = arduino1.analogRead(2); + Analog3 = arduino1.analogRead(3); + Analog4 = arduino1.analogRead(4); + + // Convert the temperature sensor: + TempADC = arduino1.analogRead(TSensor); // read the input pin + TempCalc = ((TempADC * ADCmV) - TempOffset) / TempCoef; // the ADC to C equation + + // Display the data in the Processing debug window: + println(Analog0); + println(Analog1); + println(Analog2); + println(Analog3); + println(TempCalc); + + // Send the data streams to Pachube: + dOut1.update(0, Analog0); + dOut1.update(1, Analog1); + dOut1.update(2, Analog2); + dOut1.update(3, Analog3); + dOut1.update(4, TempCalc); + + // Check for a response from Pachube; + int response = dOut1.updatePachube(); // updatePachube() updates by an authenticated PUT HTTP request + println(response); // should be 200 if successful; 401 if unauthorized; 404 if feed doesn't exist + lastUpdate = millis(); + } +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch06 The Mass Effect/CH6_1_KXM52_seismometer/CH6_1_KXM52_seismometer.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch06 The Mass Effect/CH6_1_KXM52_seismometer/CH6_1_KXM52_seismometer.pde new file mode 100644 index 0000000..aef9183 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch06 The Mass Effect/CH6_1_KXM52_seismometer/CH6_1_KXM52_seismometer.pde @@ -0,0 +1,22 @@ +/* + Seismometer using Akizuki Denshi KXM52 sensor + on scratch built Arduino 5Volt 8Mhz +*/ + +int Xaxis_pin = 3; +int Yaxis_pin = 4; +int Zaxis_pin = 5; + +void setup() +{ + Serial.begin(57600); +} + +void loop() +{ + char temp[15]; + sprintf(temp, "%d,%d,%d", + analogRead(Xaxis_pin), analogRead(Yaxis_pin), analogRead(Zaxis_pin)); + Serial.println(temp); + delay(50); +} diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch06 The Mass Effect/CH6_2_MMA7361_seismometer/CH6_2_MMA7361_seismometer.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch06 The Mass Effect/CH6_2_MMA7361_seismometer/CH6_2_MMA7361_seismometer.pde new file mode 100644 index 0000000..30c3ff0 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch06 The Mass Effect/CH6_2_MMA7361_seismometer/CH6_2_MMA7361_seismometer.pde @@ -0,0 +1,41 @@ +/* + Seismometer using SparkFun MMA7361 sensor + and Arduino Pro Mini 3.3Volt 8Mhz + + Setting GSEL + 0 = 1.5g, 800 mV/g + 1 = 6g, 206 mV/g + Sleep: 0 = Sleep, 1 = Wake + ZeroGD (output): logic high on this pin inidicates + all three axis at zero G (freefall) + + */ + +// MMA7361 control pins +int ST = 6; // Self Test +int GSEL = 7; // G-mode +int ZeroGD = 8; // Zero-g detect output +int SLP = 9; // sleep pin +// Axis outputs +int Xaxis_pin = 2; +int Yaxis_pin = 1; +int Zaxis_pin = 0; + +void setup() +{ + Serial.begin(57600); + pinMode(13, OUTPUT); + digitalWrite(13, HIGH); + digitalWrite(SLP, HIGH); //Awake + digitalWrite(GSEL, LOW); //1.5 G mode +} + +void loop() +{ + char temp[15]; + sprintf(temp, "%d,%d,%d", + analogRead(Xaxis_pin), analogRead(Yaxis_pin), analogRead(Zaxis_pin)); + Serial.println(temp); + delay(5); +} + diff --git a/Arduino Projects Save World/978-1-4302-3623-8_ch06 The Mass Effect/CH6_7_Processing_Seismometer_logger/CH6_7_Processing_Seismometer_logger.pde b/Arduino Projects Save World/978-1-4302-3623-8_ch06 The Mass Effect/CH6_7_Processing_Seismometer_logger/CH6_7_Processing_Seismometer_logger.pde new file mode 100644 index 0000000..137fd71 --- /dev/null +++ b/Arduino Projects Save World/978-1-4302-3623-8_ch06 The Mass Effect/CH6_7_Processing_Seismometer_logger/CH6_7_Processing_Seismometer_logger.pde @@ -0,0 +1,227 @@ +import processing.serial.*; + +// Zero Adjustments (around 512 +- for mount angle offsets) +int xadj=-494; +int yadj=-509; +int zadj=-755; + +int linefeed = 10; +// For storing serial port input +int sensors[] = new int[3]; +// For line drawing purposes +int old_sensors[] = new int[3]; +int xpos = 1; +// For dropping instances from the plot +int count = 0; +int count_limit = 15; + +// logging +String dataFolder = "../data/Seismo/"; +String folderName; +String logfilename; +PrintWriter logFile; +int logDay, logHour; +boolean logging = false; + + +Serial port; + +void setup() +{ + // prep screen + size(800,600,P2D); + background(0); + stroke(255,255,255); + line(0,height*1/6,width,height*1/6); + line(0,height*2/6,width,height*2/6); + line(0,height*3/6,width,height*3/6); + line(0,height*4/6,width,height*4/6); + line(0,height*5/6,width,height*5/6); + + + + // prep serial port + println(Serial.list()); + port = new Serial(this,Serial.list()[1],57600); + port.bufferUntil(linefeed); + + // logging + logDay = day(); + logHour = hour(); + folderName = dataFolder + nf(year(),4) + nf(month(),2) + + nf(day(),2) + "/"; + + logfilename = folderName + "Seismo-" + nf(year(),4) + + nf(month(),2) + nf(day(),2) + "-" + nf(hour(),2) + + nf(minute(),2) + nf(second(),2) + ".log"; + + startLogging(); +} + +void draw() +{ + if (logDay != day()) + { + logging = false; + closeLogFile(); + logDay = day(); + logHour = hour(); + + folderName = dataFolder + nf(year(),4) + nf(month(),2) + + nf(day(),2) + "/"; + + logfilename = folderName + "Seismo-" + nf(year(),4) + + nf(month(),2) + nf(day(),2) + "-" + nf(hour(),2) + + nf(minute(),2) + nf(second(),2) + ".log"; + + openLogFile(); + logging = true; + } + if (logHour != hour()) + { + logging = false; + closeLogFile(); + logHour = hour(); + + logfilename = folderName + "Seismo-" + nf(year(),4) + + nf(month(),2) + nf(day(),2) + "-" + nf(hour(),2) + + nf(minute(),2) + nf(second(),2) + ".log"; + + openLogFile(); + logging = true; + } + if(count >= count_limit) + { + count = 0; + plotSensors(); + } +} + +void serialEvent(Serial port) +{ + String input = port.readStringUntil(linefeed); + + if(input != null) + { + input = trim(input); + + sensors = int(split(input,',')); + + adjustSensors(); +// printData(); + plotSensors(); + writeLog(); + count++; + } +} + +void printData() +{ + for(int i=0; i= width) + { + xpos = 0; + background(0); + stroke(255,255,255); + line(0,height*1/6,width,height*1/6); + line(0,height*2/6,width,height*2/6); + line(0,height*3/6,width,height*3/6); + line(0,height*4/6,width,height*4/6); + line(0,height*5/6,width,height*5/6); + } + else + { + xpos++; + } +} + +String formatLogEntry() +{ + String Hour, Minute, Second; + Hour = nf(hour(),2); + Minute = nf(minute(),2); + Second = nf(second(),2); + + String log_entry = + Hour + ":" + Minute + ":" + Second + "," + + sensors[0] + "," + sensors[1] + "," + sensors[2]; + return log_entry; +} + +void writeLog() +{ + if (logging) + { + String log_entry = formatLogEntry(); + logFile.println(log_entry); + logFile.flush(); + } +} + +void startLogging() +{ + // open file + openLogFile(); + // start running + logging = true; + println("Started logging to " + logfilename); +} + +void stopLogging() +{ + logging = false; + closeLogFile(); + println("Stopped Logging."); +} + +void openLogFile() +{ + // logfilename = logfileTextField.getText(); + if (logfilename.equals("")) + { + // set tentative file name + logfilename = dataFolder + "Seismo-" + nf(year(),4) + nf(month(),2) + nf(day(),2) + + "-" + nf(hour(),2) + nf(minute(),2) + nf(second(),2) + ".log"; + } + logFile = createWriter(logfilename); + println("Log file opened: " + logfilename); +} + +void closeLogFile() +{ + logFile.flush(); + logFile.close(); + println("Log file close."); + // set tentative file name + logfilename = dataFolder + "Seismo-" + nf(year(),4) + nf(month(),2) + nf(day(),2) + + "-" + nf(hour(),2) + nf(minute(),2) + nf(second(),2) + ".log"; +} + + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..1b96ae1 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,27 @@ +Freeware License, some rights reserved + +Copyright (c) 2011 Emery Premeaux and Brian Evans + +Permission is hereby granted, free of charge, to anyone obtaining a copy +of this software and associated documentation files (the "Software"), +to work with the Software within the limits of freeware distribution and fair use. +This includes the rights to use, copy, and modify the Software for personal use. +Users are also allowed and encouraged to submit corrections and modifications +to the Software for the benefit of other users. + +It is not allowed to reuse, modify, or redistribute the Software for +commercial use in any way, or for a users educational materials such as books +or blog articles without prior permission from the copyright holder. + +The above copyright notice and this permission notice need to 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 OR APRESS 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. + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..18ebb85 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +#Apress Source Code + +This repository accompanies [*Arduino Projects to Save the World*](http://www.apress.com/9781430236238) by Emery Premeaux and Brian Evans (Apress, 2011). + +![Cover image](9781430236238.jpg) + +Download the files as a zip using the green button, or clone the repository to your machine using Git. + +##Releases + +Release v1.0 corresponds to the code in the published book, without corrections or updates. + +##Contributions + +See the file Contributing.md for more information on how you can contribute to this repository. diff --git a/contributing.md b/contributing.md new file mode 100644 index 0000000..f6005ad --- /dev/null +++ b/contributing.md @@ -0,0 +1,14 @@ +# Contributing to Apress Source Code + +Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers. + +## How to Contribute + +1. Make sure you have a GitHub account. +2. Fork the repository for the relevant book. +3. Create a new branch on which to make your change, e.g. +`git checkout -b my_code_contribution` +4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted. +5. Submit a pull request. + +Thank you for your contribution! \ No newline at end of file