Sensor with Web Server
Dependencies: EthernetInterface mbed-rpc mbed-rtos mbed
Revision 0:c385e589a779, committed 2014-04-08
- Comitter:
- afilipem
- Date:
- Tue Apr 08 12:13:32 2014 +0000
- Commit message:
- 1 version;
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DS18B20.cpp Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,105 @@ +/* +* DS18B20. Maxim DS18B20 One-Wire Thermometer. +* Uses the OneWireCRC library. +* +* Copyright (C) <2010> Petras Saduikis <petras@petras.co.uk> +* +* This file is part of OneWireThermometer. +* +* OneWireThermometer 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. +* +* OneWireThermometer 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 OneWireThermometer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "DS18B20.h" +#include "DebugTrace.h" + +DebugTrace pc_ds18B20(ON, TO_SERIAL); + +DS18B20::DS18B20(bool crcOn, bool useAddr, bool parasitic, PinName pin) : + OneWireThermometer(crcOn, useAddr, parasitic, pin, DS18B20_ID) +{ +} + + +void DS18B20::setResolution(eResolution resln) +{ + // as the write to the configuration register involves a write to the + // high and low alarm bytes, need to read these registers first + // and copy them back on the write + + BYTE read_data[THERMOM_SCRATCHPAD_SIZE]; + BYTE write_data[ALARM_CONFIG_SIZE]; + + if (readAndValidateData(read_data)) + { + // copy alarm and config data to write data + for (int k = 2; k < 5; k++) + { + write_data[k - 2] = read_data[k]; + } + int config = write_data[2]; + config &= 0x9F; + config ^= (resln << 5); + write_data[2] = config; + + resetAndAddress(); + oneWire.writeByte(WRITESCRATCH); + for (int k = 0; k < 3; k++) + { + oneWire.writeByte(write_data[k]); + } + + // remember it so we can use the correct delay in reading the temperature + // for parasitic power + resolution = resln; + } +} + +float DS18B20::calculateTemperature(BYTE* data) +{ + bool signBit = false; + if (data[TEMPERATURE_MSB] & 0x80) signBit = true; + + int read_temp = (data[TEMPERATURE_MSB] << 8) + data[TEMPERATURE_LSB]; + if (signBit) + { + read_temp = (read_temp ^ 0xFFFF) + 1; // two's complement + read_temp *= -1; + } + + //***I have a question. If the data is read earlier why it sets the resolution again now? + int resolution = (data[CONFIG_REG_BYTE] & 0x60) >> 5; // mask off bits 6,5 and move to 1,0 + switch (resolution) + { + case nineBit: // 0.5 deg C increments + read_temp &= 0xFFF8; // bits 2,1,0 are undefined + pc_ds18B20.traceOut("9 bit resolution ...\r\n"); + break; + case tenBit: // 0.25 deg C increments + read_temp &= 0xFFFC; // bits 1,0 are undefined + pc_ds18B20.traceOut("10 bit resolution ...\r\n"); + break; + case elevenBit: // 0.125 deg C increments + read_temp &= 0xFFFE; // bit 0 is undefined, ***bit 0 is 2^ + pc_ds18B20.traceOut("11 bit resolution ...\r\n"); + break; + case twelveBit: // 0.0625 deg C increments + pc_ds18B20.traceOut("12 bit resolution ...\r\n"); + break; + } + float realTemp = (float)read_temp/16 ; + + pc_ds18B20.traceOut("TEMP_READ/REAL TEMP: %f \r\n", realTemp); + + return realTemp; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DS18B20.h Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,41 @@ +/* +* DS18B20. Maxim DS18B20 One-Wire Thermometer. +* Uses the OneWireCRC library. +* +* Copyright (C) <2010> Petras Saduikis <petras@petras.co.uk> +* +* This file is part of OneWireThermometer. +* +* OneWireThermometer 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. +* +* OneWireThermometer 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 OneWireThermometer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SNATCH59_DS18B20_H +#define SNATCH59_DS18B20_H + +#include "OneWireThermometer.h" +#include "OneWireDefs.h" + +class DS18B20 : public OneWireThermometer +{ +public: + DS18B20(bool crcOn, bool useAddr, bool parasitic, PinName pin); + + virtual void setResolution(eResolution resln); + +protected: + virtual float calculateTemperature(BYTE* data); +}; + + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DS18S20.cpp Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,55 @@ +/* +* DS18S20. Maxim DS18S20 One-Wire Thermometer. +* Uses the OneWireCRC library. +* +* Copyright (C) <2010> Petras Saduikis <petras@petras.co.uk> +* +* This file is part of OneWireThermometer. +* +* OneWireThermometer 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. +* +* OneWireThermometer 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 OneWireThermometer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "DS18S20.h" +#include "DebugTrace.h" + +DebugTrace pc_ds18S20(ON, TO_SERIAL); + +DS18S20::DS18S20(bool crcOn, bool useAddr, bool parasitic, PinName pin) : + OneWireThermometer(crcOn, useAddr, parasitic, pin, DS18S20_ID) +{ +} + +float DS18S20::calculateTemperature(BYTE* data) +{ + // DS18S20 basic resolution is always 9 bits, which can be enhanced as follows + bool signBit = false; + if (data[TEMPERATURE_MSB] & 0x80) signBit = true; + + int read_temp = (data[TEMPERATURE_MSB] << 8) + data[TEMPERATURE_LSB]; + if (signBit) + { + read_temp = (read_temp ^ 0xFFFF) + 1; // two's complement + read_temp *= -1; + } + + float readTemp = (float)read_temp/2 ; // divide by 2 + pc_ds18S20.traceOut("TEMP_READ: %f \r\n", readTemp); // 9 bit resolution value + + // convert to real temperature + float tempCount = float(data[COUNT_PER_DEG_BYTE] - data[COUNT_REMAIN_BYTE])/(float)data[COUNT_PER_DEG_BYTE]; + float realTemp = (readTemp - 0.25) + tempCount; + pc_ds18S20.traceOut("Temperature: %f \r\n", realTemp); // enhanced resolution value + + return realTemp; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DS18S20.h Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,39 @@ +/* +* DS18S20. Maxim DS18S20 One-Wire Thermometer. +* Uses the OneWireCRC library. +* +* Copyright (C) <2010> Petras Saduikis <petras@petras.co.uk> +* +* This file is part of OneWireThermometer. +* +* OneWireThermometer 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. +* +* OneWireThermometer 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 OneWireThermometer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SNATCH59_DS18S20_H +#define SNATCH59_DS18S20_H + +#include "OneWireThermometer.h" + +class DS18S20 : public OneWireThermometer +{ +public: + DS18S20(bool crcOn, bool useAddr, bool parasitic, PinName pin); + + virtual void setResolution(eResolution resln) { }; // do nothing + +protected: + virtual float calculateTemperature(BYTE* data); +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DebugTrace.cpp Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,143 @@ +/* +* DebugTrace. Allows dumping debug messages/values to serial or +* to file. +* +* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk> +* +* This file is part of DebugTrace. +* +* DebugTrace 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. +* +* DebugTrace 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 DebugTrace. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "DebugTrace.h" +#include <mbed.h> +#include <stdarg.h> +#include <string.h> + +Serial logSerial(USBTX, USBRX); +LocalFileSystem local("local"); + +const char* FILE_PATH = "/local/"; +const char* EXTN = ".bak"; + +DebugTrace::DebugTrace(eLog on, eLogTarget mode, const char* fileName, int maxSize) : + enabled(on), logMode(mode), maxFileSize(maxSize), currentFileSize(0), + logFileStatus(0) +{ + // allocate memory for file name strings + int str_size = (strlen(fileName) + strlen(FILE_PATH) + strlen(EXTN) + 1) * sizeof(char); + logFile = (char*)malloc(str_size); + logFileBackup = (char*)malloc(str_size); + + // add path to log file name + strcpy(logFile, FILE_PATH); + strcat(logFile, fileName); + + // create backup file name + strcpy(logFileBackup, logFile); + strcpy(logFileBackup, strtok(logFileBackup, ".")); + strcat(logFileBackup, EXTN); +} + +DebugTrace::~DebugTrace() +{ + // dust to dust, ashes to ashes + if (logFile != NULL) free(logFile); + if (logFileBackup != NULL) free(logFileBackup); +} + +void DebugTrace::clear() +{ + // don't care about whether these fail + remove(logFile); + remove(logFileBackup); +} + +void DebugTrace::backupLog() +{ + // delete previous backup file + if (remove(logFileBackup)) + { + // standard copy stuff + char ch; + FILE* to = fopen(logFileBackup, "wb"); + if (NULL != to) + { + FILE* from = fopen(logFile, "rb"); + if (NULL != from) + { + while(!feof(from)) + { + ch = fgetc(from); + if (ferror(from)) break; + + if(!feof(from)) fputc(ch, to); + if (ferror(to)) break; + } + } + + if (NULL != from) fclose(from); + if (NULL != to) fclose(to); + } + } + + // now delete the log file, so we are ready to start again + // even if backup creation failed - the show must go on! + logFileStatus = remove(logFile); +} + +void DebugTrace::traceOut(const char* fmt, ...) +{ + if (enabled) + { + va_list ap; // argument list pointer + va_start(ap, fmt); + + if (TO_SERIAL == logMode) + { + vfprintf(logSerial, fmt, ap); + } + else // TO_FILE + { + if (0 == logFileStatus) // otherwise we failed to remove a full log file + { + // Write data to file. Note the file size may go over limit + // as we check total size afterwards, using the size written to file. + // This is not a big issue, as this mechanism is only here + // to stop the file growing unchecked. Just remember log file sizes may + // be some what over (as apposed to some what under), so don't push it + // with the max file size. + FILE* fp = fopen(logFile, "a"); + if (NULL == fp) + { + va_end(ap); + return; + } + int size_written = vfprintf(fp, fmt, ap); + fclose(fp); + + // check if we are over the max file size + // if so backup file and start again + currentFileSize += size_written; + if (currentFileSize >= maxFileSize) + { + backupLog(); + currentFileSize = 0; + } + } + } + + va_end(ap); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DebugTrace.h Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,50 @@ +/* +* DebugTrace. Allows dumping debug messages/values to serial or +* to file. +* +* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk> +* +* This file is part of DebugTrace. +* +* DebugTrace 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. +* +* DebugTrace 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 DebugTrace. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SNATCH59_DEBUGTRACE_H +#define SNATCH59_DEBUGTRACE_H + +enum eLog {OFF, ON}; +enum eLogTarget {TO_SERIAL, TO_FILE}; + +class DebugTrace +{ +public: + DebugTrace(eLog on, eLogTarget mode, const char* fileName = "log.txt", const int maxSize = 1024); + ~DebugTrace(); + + void clear(); + void traceOut(const char* fmt, ...); + +private: + eLog enabled; + eLogTarget logMode; + int maxFileSize; + int currentFileSize; + char* logFile; + char* logFileBackup; + int logFileStatus; // if things go wrong, don't write any more data to file + + void backupLog(); +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EthernetInterface.lib Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/feb11/code/EthernetInterface/#f533841d34cb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Formatter.cpp Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,194 @@ +#include "Formatter.h" +#include "mbed.h" +#include "RPCObjectManager.h" +#include "EthernetInterface.h" + +//***new addings +#include "DS18S20.h" +#include "DS18B20.h" +#include "OneWireDefs.h" +#include "DebugTrace.h" + + + +const char *SIMPLE_HTML_CODE = "\ +<!DOCTYPE html>\ +<html>\ +<head>\ +<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\ +<title>TCP Server</title>\ +</head>\ + <body>"; + + +const char* INTERACTIVE_HTML_CODE_1 = "\ +<!DOCTYPE html> \ +<html>\ +<head>\ +<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\ +<title>TCP Server</title>\ +<script type=\"text/javascript\">\ +var ip = \"%s\";\ +function submitCreateForm()\ +{\ +var list = document.getElementById(\"type\");\ +var type = list.options[list.selectedIndex].value;\ +var name = document.getElementById(\"name\").value;\ +if(name === \"\") \ +return;\ +var arg = document.getElementById(\"arg\").value;\ +var url;\ +if(arg === \"\") url = \"http://\" + ip + type + \"new?name=\" + name;\ +else url = \"http://\" + ip + type + \"new?arg=\" + arg + \"&name=\" + name;\ +location.href= url;\ +}\ +function submitCallFuncForm()\ +{\ +var command = document.getElementById(\"command\").value;\ +if(command === \"\") \ +return; \ +var tmp = command.split(\' \');\ +var url = tmp[0];\ +if(tmp.length > 1)\ +url += \"?\";\ +for(var i = 1; i < tmp.length; ++i)\ +{\ +url += \"arg\" + i + \"=\" + tmp[i];\ +if(i+1 < tmp.length)\ +url += \"&\";\ +}\ +location.href = url;\ +}\ +</script>\ +</head> \ +<body>"; + +const char* INTERACTIVE_HTML_CODE_2 = "<h3>Create Object :</h3>\ +<form>\ +Type: <select id=\"type\">\ +<option value=\"/DigitalOut/\">DigitalOut</option>\ +<option value=\"/DigitalIn/\">DigitalIn</option>\ +<option value=\"/DigitalInOut/\">DigitalInOut</option>\ +<option value=\"/PwmOut/\">PwmOut</option>\ +<option value=\"/Timer/\">Timer</option>\ +</select><br>\ +name: <input type=\"text\" id=\"name\"><br>\ +arg(optional): <input type=\"text\" id=\"arg\">\ +<p><input type=\"button\" value=\"Create\" onclick=\"javascript:submitCreateForm();\"></p>\ +</form> \ + \ +<h3>Call a function :</h3>\ +<p>Enter an RPC command.</p>\ +<form>\ +Command: <input type= \"text\" id=\"command\" maxlength=127><br>\ +<p><input type=\"button\" value=\"Send\" onclick=\"javascript:submitCallFuncForm();\"></p><br>\ +<h3>Temperature :</h3>\ +<p>Temperature in degres</p>\ +</form>\ +</body> \ +</html>"; + +static char chunk[1024]; + +Formatter::Formatter(int nb): +currentChunk(0), +nbChunk(nb) +{ +} + +char* Formatter::get_page(char *reply) +{ + chunk[0] = '\0'; + + if(currentChunk < nbChunk) + { + get_chunk(currentChunk, reply); + currentChunk++; + } + else + currentChunk = 0; + + return chunk; +} + +void Formatter::get_chunk(const int c, char *reply) +{ + strcat(chunk, reply); +} + +SimpleHTMLFormatter::SimpleHTMLFormatter(): +Formatter() +{ +} + +void SimpleHTMLFormatter::get_chunk(const int c, char* reply) +{ + strcat(chunk, SIMPLE_HTML_CODE); + + if(reply != NULL && strlen(reply) != 0) + { + strcat(chunk, "RPC reply : "); + strcat(chunk, reply); + } + + if(!RPCObjectManager::instance().is_empty()) + { + strcat(chunk, "<ul>"); + for(std::list<char*>::iterator itor = RPCObjectManager::instance().begin(); + itor != RPCObjectManager::instance().end(); + ++itor) + { + strcat(chunk, "<li>"); + strcat(chunk, *itor); + strcat(chunk, "</li>"); + } + strcat(chunk, "</ul>"); + } + + strcat(chunk, "</body></html>"); +} + +InteractiveHTMLFormatter::InteractiveHTMLFormatter(): +Formatter(3) +{ +} + +void InteractiveHTMLFormatter::get_chunk(const int c, char *reply) +{ + if(c == 0) + sprintf(chunk, INTERACTIVE_HTML_CODE_1, EthernetInterface::getIPAddress()); + + else if(c == 1) + { + if(reply != NULL && strlen(reply) != 0) + { + strcat(chunk, "RPC reply : "); + strcat(chunk, reply); + } + if(!RPCObjectManager::instance().is_empty()) + { + strcat(chunk, "<p>Objects created :</p>"); + + strcat(chunk, "<ul>"); + for(std::list<char*>::iterator itor = RPCObjectManager::instance().begin(); + itor != RPCObjectManager::instance().end(); + ++itor) + { + strcat(chunk, "<li>"); + strcat(chunk, *itor); + strcat(chunk, " (<a href=\"http://"); + strcat(chunk, EthernetInterface::getIPAddress()); + strcat(chunk, "/"); + strcat(chunk, *itor); + strcat(chunk, "/delete\">delete</a>)"); + strcat(chunk, "</li>"); + } + strcat(chunk, "</ul>"); + } + strcat(chunk, " "); + } + else if(c == 2) + strcat(chunk, INTERACTIVE_HTML_CODE_2); +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Formatter.h Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,48 @@ +#ifndef FORMATTER +#define FORMATTER + + +class Formatter +{ + public : + + Formatter(int nbChunk = 1); + + char* get_page(char *reply); + + protected : + + virtual void get_chunk(const int c, char *reply); + + private : + + int currentChunk; + int nbChunk; +}; + +class SimpleHTMLFormatter : public Formatter +{ + public : + + SimpleHTMLFormatter(); + + protected : + + virtual void get_chunk(const int c, char *reply); + +}; + +class InteractiveHTMLFormatter : public Formatter +{ + public : + + InteractiveHTMLFormatter(); + + protected : + + virtual void get_chunk(const int c, char *reply); +}; + + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPServer.cpp Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,122 @@ +#include "HTTPServer.h" + +#define INVALID_FORMATTER "No valid formatter specified" + +bool cmp(char* a, char* b) +{ + return strcmp(a,b) < 0; +} + +HTTPServer::HTTPServer(Formatter *f): +socket(), +handlers(&cmp), +formatter(f), +reply(), +command() +{ +} + +HTTPServer::~HTTPServer() +{ + for(std::map<char*, RequestHandler*>::iterator itor = handlers.begin(); + itor != handlers.end(); + ++itor) + delete itor->second; + + if(formatter) + delete formatter; +} + +bool HTTPServer::init(int port) +{ + socket.set_blocking(true); + if(socket.bind(port)) + { + printf("Could not bind on port %d.\n", port); + return false; + } + + if(socket.listen()) + { + printf("Could not listen %d\n", port); + return false; + } + + return true; +} + +void HTTPServer::run() +{ + TCPSocketConnection c; + while(true) + { + while(socket.accept(c)); + c.set_blocking(false, 1000); + while(c.is_connected()) + { + char buffer[512]; + int n = c.receive_all(buffer, sizeof(buffer)-1); + if(n == 0) + { + c.close(); + break; + } + else if(n != -1) + { + printf("Received data\n"); + buffer[n] = '\0'; + handle_request(buffer); + if(formatter != NULL) + { + printf("Sending data..."); + char *page = formatter->get_page(reply); + do + { + c.send(page, strlen(page)+1); + page = formatter->get_page(reply); + }while(strlen(page)>0); + printf("done\n"); + } + else + c.send(INVALID_FORMATTER, strlen(INVALID_FORMATTER)+1); + } + else + printf("Error while receiving data\n"); + break;//***new + } + break;//***new + } +} + +void HTTPServer::handle_request(char *buffer) +{ + char *request_type = strtok(buffer, " "); + char *request = strtok(NULL, " "); + + reply[0] = '\0'; + if(!strcmp(request, "/")) + return; + + if(!command.decode(request)) + { + strcat(reply, "Malformed request"); + return; + } + + std::map<char*, RequestHandler*>::iterator itor = handlers.find(request_type); + if(itor == handlers.end()) + { + strcat(reply, "No request handler found for this type of request."); + return; + } + if(itor->second != NULL) + itor->second->handle(command, reply); + else + strcat(reply, "Invalid request handler"); +} + +void HTTPServer::add_request_handler(char *name, RequestHandler* handler) +{ + handlers[name] = handler; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPServer.h Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,39 @@ +#ifndef HTTP_SERVER +#define HTTP_SERVER + +#include <map> + +#include "mbed.h" +#include "mbed_rpc.h" +#include "RequestHandler.h" +#include "Formatter.h" +#include "EthernetInterface.h" +#include "RPCCommand.h" + + +class HTTPServer +{ + public : + + HTTPServer(Formatter *f = new Formatter()); + virtual ~HTTPServer(); + + bool init(int port); + + void run(); + + void add_request_handler(char *name, RequestHandler* handler); + + private : + + void handle_request(char *buffer); + + TCPSocketServer socket; + std::map<char*, RequestHandler*, bool(*)(char*, char*)> handlers; + Formatter *formatter; + char reply[RPC_MAX_STRING]; + RPCCommand command; +}; + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OneWireCRC.cpp Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,459 @@ +/* +* OneWireCRC. This is a port to mbed of Jim Studt's Adruino One Wire +* library. Please see additional copyrights below this one, including +* references to other copyrights. +* +* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk> +* +* This file is part of OneWireCRC. +* +* OneWireCRC 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. +* +* OneWireCRC 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 OneWireCRC. If not, see <http://www.gnu.org/licenses/>. +*/ +/* +Copyright (c) 2007, Jim Studt + +Updated to work with arduino-0008 and to include skip() as of +2007/07/06. --RJL20 + +Modified to calculate the 8-bit CRC directly, avoiding the need for +the 256-byte lookup table to be loaded in RAM. Tested in arduino-0010 +-- Tom Pollard, Jan 23, 2008 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Much of the code was inspired by Derek Yerger's code, though I don't +think much of that remains. In any event that was.. + (copyleft) 2006 by Derek Yerger - Free to distribute freely. + +The CRC code was excerpted and inspired by the Dallas Semiconductor +sample code bearing this copyright. +//--------------------------------------------------------------------------- +// Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES +// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// Except as contained in this notice, the name of Dallas Semiconductor +// shall not be used except as stated in the Dallas Semiconductor +// Branding Policy. +//-------------------------------------------------------------------------- +*/ + +#include "OneWireCRC.h" +#include "OneWireDefs.h" + +// recommended data sheet timings in micro seconds +const int standardT[] = {6, 64, 60, 10, 9, 55, 0, 480, 70, 410}; +const int overdriveT[] = {1.5, 7.5, 7.5, 2.5, 0.75, 7, 2.5, 70, 8.5, 40}; + +OneWireCRC::OneWireCRC(PinName oneWire, eSpeed speed) : oneWirePort(oneWire) +{ + if (STANDARD == speed) timing = standardT; + else timing = overdriveT; // overdrive + + resetSearch(); // reset address search state +} + +// Generate a 1-wire reset, return 1 if no presence detect was found, +// return 0 otherwise. +// (NOTE: does not handle alarm presence from DS2404/DS1994) +int OneWireCRC::reset() +{ + + BYTE result = 0; // sample presence pulse result + + wait_us(timing[6]); + oneWirePort.output(); + oneWirePort = 0; + wait_us(timing[7]); + oneWirePort.input(); + wait_us(timing[8]); + result = !(oneWirePort & 0x01); + wait_us(timing[9]); + + return result; +} + +// +// Write a bit. Port and bit is used to cut lookup time and provide +// more certain timing. +// +void OneWireCRC::writeBit(int bit) +{ + bit = bit & 0x01; + + if (bit) + { + // Write '1' bit + oneWirePort.output(); + oneWirePort = 0; + wait_us(timing[0]); + oneWirePort.input(); + wait_us(timing[1]); + } + else + { + // Write '0' bit + oneWirePort.output(); + oneWirePort = 0; + wait_us(timing[2]); + oneWirePort.input(); + wait_us(timing[3]); + } +} + +// +// Read a bit. Port and bit is used to cut lookup time and provide +// more certain timing. +// +int OneWireCRC::readBit() +{ + BYTE result; + + oneWirePort.output(); + oneWirePort = 0; + wait_us(timing[0]); + oneWirePort.input(); + wait_us(timing[4]); + result = oneWirePort & 0x01; + wait_us(timing[5]); + + return result; +} + +// +// Write a byte. The writing code uses the active drivers to raise the +// pin high, if you need power after the write (e.g. DS18S20 in +// parasite power mode) then set 'power' to 1, otherwise the pin will +// go tri-state at the end of the write to avoid heating in a short or +// other mishap. +// +void OneWireCRC::writeByte(int data) +{ + // Loop to write each bit in the byte, LS-bit first + for (int loop = 0; loop < 8; loop++) + { + writeBit(data & 0x01); + + // shift the data byte for the next bit + data >>= 1; + } +} + +// +// Read a byte +// +int OneWireCRC::readByte() +{ + int result = 0; + + for (int loop = 0; loop < 8; loop++) + { + // shift the result to get it ready for the next bit + result >>= 1; + + // if result is one, then set MS bit + if (readBit()) result |= 0x80; + } + + return result; +} + +int OneWireCRC::touchByte(int data) +{ + int result = 0; + + for (int loop = 0; loop < 8; loop++) + { + // shift the result to get it ready for the next bit + result >>= 1; + + // If sending a '1' then read a bit else write a '0' + if (data & 0x01) + { + if (readBit()) result |= 0x80; + } + else writeBit(0); + + // shift the data byte for the next bit + data >>= 1; + } + + return result; +} + +void OneWireCRC::block(BYTE* data, int data_len) +{ + for (int loop = 0; loop < data_len; loop++) + { + data[loop] = touchByte(data[loop]); + } +} + +int OneWireCRC::overdriveSkip(BYTE* data, int data_len) +{ + // set the speed to 'standard' + timing = standardT; + + // reset all devices + if (reset()) return 0; // if no devices found + + // overdrive skip command + writeByte(OVERDRIVE_SKIP); + + // set the speed to 'overdrive' + timing = overdriveT; + + // do a 1-Wire reset in 'overdrive' and return presence result + return reset(); +} + +// +// Do a ROM select +// +void OneWireCRC::matchROM(BYTE rom[8]) +{ + writeByte(MATCH_ROM); // Choose ROM + + for(int i = 0; i < 8; i++) writeByte(rom[i]); +} + +// +// Do a ROM skip +// +void OneWireCRC::skipROM() +{ + writeByte(SKIP_ROM); // Skip ROM +} + +// +// You need to use this function to start a search again from the beginning. +// You do not need to do it for the first search, though you could. +// +void OneWireCRC::resetSearch() +{ + searchJunction = -1; + searchExhausted = false; + for (int i = 0; i < 8; i++) + { + address[i] = 0; + } +} + +// +// Perform a search. If this function returns a '1' then it has +// enumerated the next device and you may retrieve the ROM from the +// OneWire::address variable. If there are no devices, no further +// devices, or something horrible happens in the middle of the +// enumeration then a 0 is returned. If a new device is found then +// its address is copied to newAddr. Use OneWire::reset_search() to +// start over. +// +BYTE OneWireCRC::search(BYTE* newAddr) +{ + BYTE i; + int lastJunction = -1; + BYTE done = 1; + + if (searchExhausted) return 0; + + if (!reset()) return 0; + + writeByte(SEARCH_ROM); + + for(i = 0; i < 64; i++) + { + BYTE a = readBit( ); + BYTE nota = readBit( ); + BYTE ibyte = i/8; + BYTE ibit = 1 << (i & 7); + + // I don't think this should happen, this means nothing responded, but maybe if + // something vanishes during the search it will come up. + if (a && nota) return 0; + + if (!a && !nota) + { + if (i == searchJunction) + { + // this is our time to decide differently, we went zero last time, go one. + a = 1; + searchJunction = lastJunction; + } + else if (i < searchJunction) + { + // take whatever we took last time, look in address + if (address[ibyte] & ibit) a = 1; + else + { + // Only 0s count as pending junctions, we've already exhasuted the 0 side of 1s + a = 0; + done = 0; + lastJunction = i; + } + } + else + { + // we are blazing new tree, take the 0 + a = 0; + searchJunction = i; + done = 0; + } + lastJunction = i; + } + + if (a) address[ibyte] |= ibit; + else address[ibyte] &= ~ibit; + + writeBit(a); + } + + if (done) searchExhausted = true; + + for (i = 0; i < 8; i++) newAddr[i] = address[i]; + + return 1; +} + +// The 1-Wire CRC scheme is described in Maxim Application Note 27: +// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products" +// + +#if ONEWIRE_CRC8_TABLE +// This table comes from Dallas sample code where it is freely reusable, +// though Copyright (C) 2000 Dallas Semiconductor Corporation +static BYTE dscrc_table[] = +{ + 0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65, + 157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220, + 35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98, + 190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255, + 70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7, + 219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154, + 101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36, + 248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185, + 140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205, + 17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80, + 175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238, + 50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115, + 202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139, + 87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22, + 233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168, + 116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53}; + +// +// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM +// and the registers. (note: this might better be done without the +// table, it would probably be smaller and certainly fast enough +// compared to all those delayMicrosecond() calls. But I got +// confused, so I use this table from the examples.) +// +BYTE OneWireCRC::crc8(BYTE* addr, BYTE len) +{ + BYTE i; + BYTE crc = 0; + + for (i = 0; i < len; i++) + { + crc = dscrc_table[crc ^ addr[i] ]; + } + + return crc; +} +#else +// +// Compute a Dallas Semiconductor 8 bit CRC directly. +// +BYTE OneWireCRC::crc8(BYTE* addr, BYTE len) +{ + BYTE i, j; + BYTE crc = 0; + + for (i = 0; i < len; i++) + { + BYTE inbyte = addr[i]; + for (j = 0; j < 8; j++) + { + BYTE mix = (crc ^ inbyte) & 0x01; + crc >>= 1; + if (mix) crc ^= 0x8C; + inbyte >>= 1; + } + } + + return crc; +} +#endif + +static short oddparity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; + +// +// Compute a Dallas Semiconductor 16 bit CRC. I have never seen one of +// these, but here it is. +// +unsigned short OneWireCRC::crc16(unsigned short* data, unsigned short len) +{ + unsigned short i; + unsigned short crc = 0; + + for ( i = 0; i < len; i++) + { + unsigned short cdata = data[len]; + + cdata = (cdata ^ (crc & 0xff)) & 0xff; + crc >>= 8; + + if (oddparity[cdata & 0xf] ^ oddparity[cdata >> 4]) crc ^= 0xc001; + + cdata <<= 6; + crc ^= cdata; + cdata <<= 1; + crc ^= cdata; + } + + return crc; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OneWireCRC.h Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,138 @@ +/* +* OneWireCRC. This is a port to mbed of Jim Studt's Adruino One Wire +* library. Please see additional copyrights below this one, including +* references to other copyrights. +* +* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk> +* +* This file is part of OneWireCRC. +* +* OneWireCRC 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. +* +* OneWireCRC 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 OneWireCRC. If not, see <http://www.gnu.org/licenses/>. +*/ +/* +Copyright (c) 2007, Jim Studt + +Updated to work with arduino-0008 and to include skip() as of +2007/07/06. --RJL20 + +Modified to calculate the 8-bit CRC directly, avoiding the need for +the 256-byte lookup table to be loaded in RAM. Tested in arduino-0010 +-- Tom Pollard, Jan 23, 2008 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Much of the code was inspired by Derek Yerger's code, though I don't +think much of that remains. In any event that was.. + (copyleft) 2006 by Derek Yerger - Free to distribute freely. + +The CRC code was excerpted and inspired by the Dallas Semiconductor +sample code bearing this copyright. +*/ +//--------------------------------------------------------------------------- +// Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES +// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// Except as contained in this notice, the name of Dallas Semiconductor +// shall not be used except as stated in the Dallas Semiconductor +// Branding Policy. +//-------------------------------------------------------------------------- + +#ifndef SNATCH59_ONEWIRECRC_H +#define SNATCH59_ONEWIRECRC_H + +#include <mbed.h> + +// Select the table-lookup method of computing the 8-bit CRC by setting this to 1 +#ifndef ONEWIRE_CRC8_TABLE +#define ONEWIRE_CRC8_TABLE 1 +#endif + +typedef unsigned char BYTE; // used to be uint8_t : something a byte wide, whatever .... + +enum eSpeed {OVERDRIVE, STANDARD}; + +class OneWireCRC +{ +public: + OneWireCRC(PinName oneWire, eSpeed); + + // reset, read, write functions + int reset(); + void writeByte(int data); + int readByte(); + int touchByte(int data); + void block(BYTE* data, int data_len); + int overdriveSkip(BYTE* data, int data_len); + + // address functions + void matchROM(BYTE rom[8]); + void skipROM(); + + // address search functions + void resetSearch(); + BYTE search(BYTE* newAddr); + + // CRC check functions + static BYTE crc8(BYTE* addr, BYTE len); + static unsigned short crc16(unsigned short* data, unsigned short len); + +private: + const int* timing; + + BYTE address[8]; + int searchJunction; // so we can set to it -1 somewhere + bool searchExhausted; + + DigitalInOut oneWirePort; + + // read/write bit functions + void writeBit(int bit); + int readBit(); +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OneWireDefs.h Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,66 @@ +/* +* OneWireCRC. This is a port to mbed of Jim Studt's Adruino One Wire +* library. +* +* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk> +* +* This file is part of OneWireCRC. +* +* OneWireCRC 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. +* +* OneWireCRC 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 OneWireCRC. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SNATCH59_ONEWIREDEFS_H +#define SNATCH59_ONEWIREDEFS_H + +// device ids +#define DS18B20_ID 0x28 +#define DS18S20_ID 0x10 + +#define ALARM_CONFIG_SIZE 3 +#define THERMOM_SCRATCHPAD_SIZE 9 +#define THERMOM_CRC_BYTE 8 +#define ADDRESS_SIZE 8 +#define ADDRESS_CRC_BYTE 7 + +// One Wire command codes +#define OVERDRIVE_SKIP 0x3C +// ROM commands +#define SEARCH_ROM 0xF0 +#define READ_ROM 0x33 +#define MATCH_ROM 0x55 +#define SKIP_ROM 0xCC +#define ALARM_SEARCH 0xEC +// Functions Commnds +#define CONVERT 0x44 +#define WRITESCRATCH 0x4E +#define READSCRATCH 0xBE +#define COPYSCRATCH 0x48 +#define RECALLE2 0xB8 +#define READPOWERSUPPLY 0xB4 + +// temperature read resolutions +enum eResolution {nineBit = 0, tenBit, elevenBit, twelveBit}; +const int CONVERSION_TIME[] = {94, 188, 375, 750}; // milli-seconds + +// DS18B20/DS18S20 related +#define TEMPERATURE_LSB 0 +#define TEMPERATURE_MSB 1 +#define HIGH_ALARM_BYTE 2 +#define LOW_ALARM_BYTE 3 +#define CONFIG_REG_BYTE 4 +#define CONFIG_READ_END 5 +#define COUNT_REMAIN_BYTE 6 +#define COUNT_PER_DEG_BYTE 7 + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OneWireThermometer.cpp Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,167 @@ +/* +* OneWireThermometer. Base class for Maxim One-Wire Thermometers. +* Uses the OneWireCRC library. +* +* Copyright (C) <2010> Petras Saduikis <petras@petras.co.uk> +* +* This file is part of OneWireThermometer. +* +* OneWireThermometer 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. +* +* OneWireThermometer 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 OneWireThermometer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "OneWireThermometer.h" +#include "OneWireDefs.h" +#include "DebugTrace.h" + +DebugTrace pc(ON, TO_SERIAL); + +// constructor specifies standard speed for the 1-Wire comms +OneWireThermometer::OneWireThermometer(bool crcOn, bool useAddr, bool parasitic, PinName pin, int device_id) : + useCRC(crcOn), useAddress(useAddr), useParasiticPower(parasitic), + oneWire(pin, STANDARD), deviceId(device_id), resolution(twelveBit) +{ + // NOTE: the power-up resolution of a DS18B20 is 12 bits. The DS18S20's resolution is always + // 9 bits + enhancement, but we treat the DS18S20 as fixed to 12 bits for calculating the + // conversion time Tconv. +} + +bool OneWireThermometer::initialize() +{ + // get the device address for use in selectROM() when reading the temperature + // - not really needed except for device validation if using skipROM() + if (useAddress) + { + pc.traceOut("\r\n"); + pc.traceOut("New Scan\r\n"); + + oneWire.resetSearch(); + if (!oneWire.search(address)) // search for 1-wire device address + { + pc.traceOut("No more addresses.\r\n"); + wait(2); + return false; + } + + pc.traceOut("Address = "); + for (int i = 0; i < ADDRESS_SIZE; i++) + { + pc.traceOut("%x ", (int)address[i]); + } + pc.traceOut("\r\n"); + + if (OneWireCRC::crc8(address, ADDRESS_CRC_BYTE) != address[ADDRESS_CRC_BYTE]) // check address CRC is valid + { + pc.traceOut("CRC is not valid!\r\n"); + wait(2); + return false; + } + + if (address[0] != deviceId) + { + // Make sure it is a one-wire thermometer device + if (DS18B20_ID == deviceId) + pc.traceOut("You need to use a DS1820 or DS18S20 for correct results.\r\n"); + else if (DS18S20_ID == deviceId) + pc.traceOut("You need to use a DS18B20 for correct results.\r\n"); + else + pc.traceOut("Device is not a DS18B20/DS1820/DS18S20 device.\r\n"); + + wait(2); + return false; + } + else + { + if (DS18B20_ID == deviceId) pc.traceOut("DS18B20 present and correct.\r\n"); + if (DS18S20_ID == deviceId) pc.traceOut("DS1820/DS18S20 present and correct.\r\n"); + } + } + + return true; +} + +// NOTE ON USING SKIP ROM: ok to use before a Convert command to get all +// devices on the bus to do simultaneous temperature conversions. BUT can +// only use before a Read Scratchpad command if there is only one device on the +// bus. For purpose of this library it is assumed there is only one device +// on the bus. +void OneWireThermometer::resetAndAddress() +{ + oneWire.reset(); // reset device + if (useAddress) + { + oneWire.matchROM(address); // select which device to talk to + } + else + { + oneWire.skipROM(); // broadcast + } +} + +bool OneWireThermometer::readAndValidateData(BYTE* data) +{ + bool dataOk = true; + + resetAndAddress(); + oneWire.writeByte(READSCRATCH); // read Scratchpad + + pc.traceOut("read = "); + for (int i = 0; i < THERMOM_SCRATCHPAD_SIZE; i++) + { + // we need all bytes which includes CRC check byte + data[i] = oneWire.readByte(); + pc.traceOut("%x ", (int)data[i]); + } + pc.traceOut("\r\n"); + + // Check CRC is valid if you want to + if (useCRC && !(OneWireCRC::crc8(data, THERMOM_CRC_BYTE) == data[THERMOM_CRC_BYTE])) + { + // CRC failed + pc.traceOut("CRC FAILED... \r\n"); + dataOk = false; + } + + return dataOk; +} + +float OneWireThermometer::readTemperature() +{ + BYTE data[THERMOM_SCRATCHPAD_SIZE]; + float realTemp = -999; + + resetAndAddress(); + oneWire.writeByte(CONVERT); // issue Convert command + + if (useParasiticPower) + { + // wait while converting - Tconv (according to resolution of reading) + wait_ms(CONVERSION_TIME[resolution]); + } + else + { + // TODO + // after the Convert command, the device should respond by transmitting 0 + // while the temperature conversion is in progress and 1 when the conversion is done + // - as were are not checking this (TODO), we use Tconv, as we would do for + // parasitic power + wait_ms(CONVERSION_TIME[resolution]); + } + + if (readAndValidateData(data)) // issue Read Scratchpad commmand and get data + { + realTemp = calculateTemperature(data); + } + + return realTemp; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OneWireThermometer.h Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,57 @@ +/* +* OneWireThermometer. Base class for Maxim One-Wire Thermometers. +* Uses the OneWireCRC library. +* +* Copyright (C) <2010> Petras Saduikis <petras@petras.co.uk> +* +* This file is part of OneWireThermometer. +* +* OneWireThermometer 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. +* +* OneWireThermometer 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 OneWireThermometer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SNATCH59_ONEWIRETHERMOMETER_H +#define SNATCH59_ONEWIRETHERMOMETER_H + +#include <mbed.h> +#include "OneWireCRC.h" +#include "OneWireDefs.h" + +typedef unsigned char BYTE; // something a byte wide + +class OneWireThermometer +{ +public: + OneWireThermometer(bool crcOn, bool useAddr, bool parasitic, PinName pin, int device_id); + + bool initialize(); + float readTemperature(); + virtual void setResolution(eResolution resln) = 0; + +protected: + const bool useParasiticPower; + const bool useCRC; + const bool useAddress; + const int deviceId; + + eResolution resolution; + BYTE address[8]; + + OneWireCRC oneWire; + + void resetAndAddress(); + bool readAndValidateData(BYTE* data); + virtual float calculateTemperature(BYTE* data) = 0; // device specific +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RPCCommand.cpp Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,130 @@ +#include "RPCCommand.h" +#include "mbed.h" +#include "RPCType.h" + + +RPCCommand::RPCCommand(): +cmd(), +obj_name(NULL), +func_name(NULL) +{ + +} + +bool RPCCommand::decode(char *buffer) +{ + if(buffer == NULL) + return false; + if(buffer[0] != '/') + return false; + + ++buffer; + char *tmp = strchr(buffer ,'/'); + + if(tmp == NULL) + return false; + if(tmp == buffer) + return false; + + tmp[0] = '\0'; + obj_name = buffer; + + buffer = tmp+1; + + if(buffer[0] == '\0' || buffer[0] == '?') + return false; + + func_name = buffer; + + tmp = strchr(buffer, '?'); + if(tmp != NULL) + { + if(tmp[1] == '\0') + return false; + tmp[0] = '\0'; + } + + cmd[0] = '\0'; + strcat(cmd, "/"); + strcat(cmd, obj_name); + strcat(cmd, "/"); + strcat(cmd, func_name); + + if(tmp == NULL) + return true; + + buffer = tmp+1; + do + { + tmp = strchr(buffer, '&'); + + if(tmp != NULL) + { + if(tmp[1] == '\0' || buffer == tmp) + return false; + tmp[0] = '\0'; + } + + char *sep = strchr(buffer, '='); + if(sep == NULL) + return false; + if(sep == buffer) + return false; + if(sep[1] == '\0' || sep[1] == '&') + return false; + + strcat(cmd, " "); + strcat(cmd, sep+1); + + if(tmp != NULL) + buffer = tmp+1; + else + buffer = NULL; + }while(buffer); + + return true; +} + + + +char* RPCCommand::get_cmd() const +{ + return (char*)cmd; +} + +RPC_COMMAND_TYPE RPCCommand::get_type() const +{ + if(!strcmp(func_name, "new") && RPCType::instance().is_supported_type(obj_name)) + return CREATE; + + RPC* r = RPC::lookup(obj_name); + if(r == NULL) + return INVALID; + + if(!strcmp(func_name, "delete")) + return DELETE; + + const struct rpc_method *methods = r->get_rpc_methods(); + int i = 0; + while(methods[i].name != NULL) + { + if(!strcmp(func_name, methods[i].name)) + { + return FUNCTION_CALL; + } + ++i; + } + + return INVALID; +} + +char* RPCCommand::get_obj_name() const +{ + return obj_name; +} + +char* RPCCommand::get_func_name() const +{ + return func_name; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RPCCommand.h Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,36 @@ +#ifndef RPCCOMMAND +#define RPCCOMMAND + +#include <list> +#include "mbed_rpc.h" + +enum RPC_COMMAND_TYPE { INVALID, CREATE, DELETE, FUNCTION_CALL }; + +struct rpc_arg +{ + char *name; + char *val; +}; + +class RPCCommand +{ + public : + + RPCCommand(); + + bool decode(char *buffer); + + char* get_cmd() const; + RPC_COMMAND_TYPE get_type() const; + char* get_obj_name() const; + char* get_func_name() const; + + private : + + char cmd[RPC_MAX_STRING]; + char* obj_name; + char* func_name; +}; + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RPCObjectManager.cpp Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,68 @@ +#include "RPCObjectManager.h" +#include "mbed.h" + +RPCObjectManager& RPCObjectManager::instance() +{ + static RPCObjectManager om; + return om; +} + +RPCObjectManager::RPCObjectManager(): +objects() +{ +} + +RPCObjectManager::~RPCObjectManager() +{ + for(std::list<char*>::iterator itor = objects.begin(); + itor != objects.end(); + ++itor) + delete *itor; +} + +void RPCObjectManager::store_object(char *obj_name) +{ + char *obj = new char[strlen(obj_name)+1]; + strcpy(obj, obj_name); + obj[strlen(obj_name)] = '\0'; + objects.push_back(obj); +} + +void RPCObjectManager::remove_object(char *obj_name) +{ + for(std::list<char*>::iterator itor = objects.begin(); + itor != objects.end(); + ++itor) + if(!strcmp(obj_name, *itor)) + { + delete *itor; + objects.erase(itor); + break; + } +} + +bool RPCObjectManager::lookup_object(char *obj_name) +{ + for(std::list<char*>::iterator itor = objects.begin(); + itor != objects.end(); + ++itor) + if(!strcmp(obj_name, *itor)) + return true; + return false; +} + +bool RPCObjectManager::is_empty() +{ + return objects.empty(); +} + +std::list<char*>::iterator RPCObjectManager::begin() +{ + return objects.begin(); +} + +std::list<char*>::iterator RPCObjectManager::end() +{ + return objects.end(); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RPCObjectManager.h Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,29 @@ +#ifndef RPCOBJECTMANAGER +#define RPCOBJECTMANAGER + +#include <list> + +class RPCObjectManager +{ + public : + + static RPCObjectManager& instance(); + + void store_object(char *obj_name); + void remove_object(char *obj_name); + bool lookup_object(char *obj_name); + + std::list<char*>::iterator begin(); + std::list<char*>::iterator end(); + + bool is_empty(); + + private : + + RPCObjectManager(); + ~RPCObjectManager(); + + std::list<char*> objects; +}; +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RPCType.cpp Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,55 @@ +#include "mbed.h" +#include "mbed_rpc.h" +#include "RPCType.h" + + +RPCType::RPCType(): +supported_types() +{ +} + +RPCType& RPCType::instance() +{ + static RPCType t; + return t; +} + +void RPCType::register_types() +{ + RPCType &t = instance(); + + RPC::add_rpc_class<RpcDigitalOut>(); + t.supported_types.push_back("DigitalOut"); + RPC::add_rpc_class<RpcDigitalIn>(); + t.supported_types.push_back("DigitalIn"); + RPC::add_rpc_class<RpcDigitalInOut>(); + t.supported_types.push_back("DigitalInOut"); + + #if DEVICE_PWMOUT + RPC::add_rpc_class<RpcPwmOut>(); + t.supported_types.push_back("PwmOut"); + #endif + #if DEVICE_SPI + t.supported_types.push_back("SPI"); + RPC::add_rpc_class<RpcSPI>(); + #endif + #if DEVICE_SERIAL + t.supported_types.push_back("Serial"); + RPC::add_rpc_class<RpcSerial>(); + #endif + RPC::add_rpc_class<RpcTimer>(); + t.supported_types.push_back("Timer"); +} + +bool RPCType::is_supported_type(char *type) +{ + for(std::list<char*>::iterator itor = instance().supported_types.begin(); + itor != instance().supported_types.end(); + ++itor) + if(!strcmp(*itor,type)) + return true; + + return false; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RPCType.h Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,23 @@ +#ifndef RPCTYPE_H +#define RPCTYPE_H + +#include <list> + +class RPCType +{ + public : + + static RPCType& instance(); + + void register_types(); + + bool is_supported_type(char *type); + + private : + + RPCType(); + std::list<char*> supported_types; +}; + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RequestHandler.cpp Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,109 @@ +#include "RequestHandler.h" +#include "mbed_rpc.h" +#include "RPCObjectManager.h" +#include "RPCCommand.h" + +const char* INVALID_CMD = "Invalid RPC command"; +const char* DELETE_ERROR = "You must send a DELETE request to remove an object "; +const char* CREATE_ERROR = "You must send a PUT request to create an object"; +const char* FUNC_CALL_ERROR = "You must send a GET request to call a function"; + +void GetRequestHandler::handle(const RPCCommand& cmd, char *reply) +{ + switch(cmd.get_type()) + { + case DELETE: + printf("Error: %s\n", DELETE_ERROR); + strcat(reply, DELETE_ERROR); + break; + case FUNCTION_CALL: + RPC::call(cmd.get_cmd(), reply); + break; + case CREATE: + printf("Error: %s\n", CREATE_ERROR); + strcat(reply, CREATE_ERROR); + break; + default: + printf("Error: %s\n", INVALID_CMD); + strcat(reply, INVALID_CMD); + break; + } +} + +void PutRequestHandler::handle(const RPCCommand& cmd, char *reply) +{ + switch(cmd.get_type()) + { + case DELETE: + printf("Error: %s\n", DELETE_ERROR); + strcat(reply, DELETE_ERROR); + break; + case FUNCTION_CALL: + printf("Error: %s\n", FUNC_CALL_ERROR); + strcat(reply, FUNC_CALL_ERROR); + break; + case CREATE: + RPC::call(cmd.get_cmd(), reply); + if(strlen(reply) > 0) + { + RPCObjectManager::instance().store_object(reply); + strcat(reply, " has been created"); + } + else + { + printf("Error while creating object\n"); + strcat(reply, "Error while creating object."); + } + break; + default: + printf("Error: %s\n", INVALID_CMD); + strcat(reply, INVALID_CMD); + break; + } +} + +void DeleteRequestHandler::handle(const RPCCommand& cmd, char *reply) +{ + switch(cmd.get_type()) + { + case CREATE: + printf("Error: %s\n", CREATE_ERROR); + strcat(reply, CREATE_ERROR); + break; + case FUNCTION_CALL: + printf("Error: %s\n", FUNC_CALL_ERROR); + strcat(reply, FUNC_CALL_ERROR); + break; + case DELETE: + RPC::call(cmd.get_cmd(), reply); + RPCObjectManager::instance().remove_object(cmd.get_obj_name()); + strcat(reply, "Deleted object "); + strcat(reply, cmd.get_obj_name()); + break; + default: + printf("Error: %s\n", INVALID_CMD); + strcat(reply, INVALID_CMD); + break; + } +} + +void ComplexRequestHandler::handle(const RPCCommand& cmd, char *reply) +{ + switch(cmd.get_type()) + { + case CREATE : + putHandler.handle(cmd, reply); + break; + case DELETE : + deleteHandler.handle(cmd, reply); + break; + case FUNCTION_CALL : + getHandler.handle(cmd, reply); + break; + default : + printf("Error: %s\n", INVALID_CMD); + strcat(reply, INVALID_CMD); + break; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RequestHandler.h Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,51 @@ +#ifndef REQUEST_HANDLER +#define REQUEST_HANDLER + +#include "RPCCommand.h" + +class RequestHandler +{ + public : + + virtual void handle(const RPCCommand& cmd, char* reply) = 0; +}; + +class GetRequestHandler : public RequestHandler +{ + public : + + virtual void handle(const RPCCommand& cmd, char* reply); +}; + +class PutRequestHandler : public RequestHandler +{ + public : + + virtual void handle(const RPCCommand& cmd, char* reply); + +}; + + +class DeleteRequestHandler : public RequestHandler +{ + public : + + virtual void handle(const RPCCommand& cmd, char* reply); + +}; + +class ComplexRequestHandler : public RequestHandler +{ + public : + + virtual void handle(const RPCCommand& cmd, char* reply); + + private : + + GetRequestHandler getHandler; + PutRequestHandler putHandler; + DeleteRequestHandler deleteHandler; +}; + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,124 @@ +//*********************************** +//Blend of Ethernet Code with OneWire +//*********************************** + +#include "mbed.h" +#include "EthernetInterface.h" +#include "mbed_rpc.h" +#include "RPCCommand.h" +#include "HTTPServer.h" +#include "Formatter.h" +#include "RequestHandler.h" +#include "RPCType.h" + +#define SERVER_PORT 80 + +#include <mbed.h> +#include "DS18S20.h" +#include "DS18B20.h" +#include "OneWireDefs.h" +//***new adding +#include "DebugTrace.h" + +//#define THERMOMETER DS18S20 +#define THERMOMETER DS18B20 + +//***new adding +DigitalOut relay(p21); +//***new adding +float realTemp = -999; +//***new adding +DebugTrace pc_ds18B20B(ON, TO_SERIAL); + +HTTPServer create_simple_server() +{ + HTTPServer srv; + srv.add_request_handler("DELETE", new DeleteRequestHandler()); + srv.add_request_handler("GET", new GetRequestHandler()); + srv.add_request_handler("PUT", new PutRequestHandler()); + return srv; +} + +HTTPServer create_interactive_server() +{ + HTTPServer srv(new InteractiveHTMLFormatter()); + srv.add_request_handler("GET", new ComplexRequestHandler()); + return srv; +} + +int main(void) +{ + // device( crcOn, useAddress, parasitic, mbed pin ) + THERMOMETER device(true, true, false, p25); + + while (!device.initialize()); // keep calling until it works + + while (true) + { + RPCType::instance().register_types(); + device.setResolution(twelveBit); + realTemp=device.readTemperature(); + + if (realTemp<24) + { + relay=1; + pc_ds18B20B.traceOut("Less than 24"); + EthernetInterface eth; + if(eth.init()) + { + printf("Error while initializing the ethernet interface.\n"); + return -1; + } + if(eth.connect()) + { + printf("Error while starting the ethernet interface.\n"); + return -1; + } + + printf("IP Address is %s\n", eth.getIPAddress()); + + HTTPServer srv = create_interactive_server(); + + if(!srv.init(SERVER_PORT)) + { + eth.disconnect(); + return -1; + } + + srv.run(); + } + if (realTemp>=24) + { + relay=0; + pc_ds18B20B.traceOut("More than 24"); + EthernetInterface eth; + if(eth.init()) + { + printf("Error while initializing the ethernet interface.\n"); + return -1; + } + if(eth.connect()) + { + printf("Error while starting the ethernet interface.\n"); + return -1; + } + + printf("IP Address is %s\n", eth.getIPAddress()); + + HTTPServer srv = create_interactive_server(); + + if(!srv.init(SERVER_PORT)) + { + eth.disconnect(); + return -1; + } + + srv.run(); + } + wait(5); + } + + return EXIT_SUCCESS; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-rpc.lib Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed-rpc/#1ecadde1c929
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-rtos.lib Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed-rtos/#58b30ac3f00e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Tue Apr 08 12:13:32 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/6473597d706e \ No newline at end of file