Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 73:a91805f9e9f0, committed 2019-01-22
- Comitter:
- HelGast95
- Date:
- Tue Jan 22 08:36:23 2019 +0000
- Parent:
- 72:584fc328cad6
- Child:
- 74:12b9444a2fb4
- Commit message:
- Primera version concurrencia con servicio GATT BLE
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/source/libraries/picojson.h Tue Jan 22 08:36:23 2019 +0000
@@ -0,0 +1,820 @@
+/* Copyright 2009 Cybozu Labs, Inc.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CYBOZU LABS, INC. ``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 CYBOZU LABS, INC. 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.
+ *
+ * The views and conclusions contained in the software and documentation are
+ * those of the authors and should not be interpreted as representing official
+ * policies, either expressed or implied, of Cybozu Labs, Inc.
+ *
+ */
+#ifndef picojson_h
+#define picojson_h
+
+#include <cassert>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <iterator>
+#include <map>
+#include <string>
+#include <vector>
+
+#ifdef _MSC_VER
+ #define SNPRINTF _snprintf_s
+ #pragma warning(push)
+ #pragma warning(disable : 4244) // conversion from int to char
+#else
+ #define SNPRINTF snprintf
+#endif
+
+namespace picojson {
+
+ enum {
+ null_type,
+ boolean_type,
+ number_type,
+ string_type,
+ array_type,
+ object_type
+ };
+
+ struct null {};
+
+ class value {
+ public:
+ typedef std::vector<value> array;
+ typedef std::map<std::string, value> object;
+ protected:
+ int type_;
+ union {
+ bool boolean_;
+ double number_;
+ std::string* string_;
+ array* array_;
+ object* object_;
+ };
+ public:
+ value();
+ value(int type, bool);
+ explicit value(bool b);
+ explicit value(double n);
+ explicit value(const std::string& s);
+ explicit value(const array& a);
+ explicit value(const object& o);
+ ~value();
+ value(const value& x);
+ value& operator=(const value& x);
+ template <typename T> bool is() const;
+ template <typename T> const T& get() const;
+ template <typename T> T& get();
+ operator bool() const;
+ const value& get(size_t idx) const;
+ const value& get(const std::string& key) const;
+ std::string to_str() const;
+ template <typename Iter> void serialize(Iter os) const;
+ std::string serialize() const;
+ };
+
+ typedef value::array array;
+ typedef value::object object;
+
+ inline value::value() : type_(null_type) {}
+
+ inline value::value(int type, bool) : type_(type) {
+ switch (type) {
+#define INIT(p, v) case p##type: p = v; break
+ INIT(boolean_, false);
+ INIT(number_, 0.0);
+ INIT(string_, new std::string());
+ INIT(array_, new array());
+ INIT(object_, new object());
+#undef INIT
+ default: break;
+ }
+ }
+
+ inline value::value(bool b) : type_(boolean_type) {
+ boolean_ = b;
+ }
+
+ inline value::value(double n) : type_(number_type) {
+ number_ = n;
+ }
+
+ inline value::value(const std::string& s) : type_(string_type) {
+ string_ = new std::string(s);
+ }
+
+ inline value::value(const array& a) : type_(array_type) {
+ array_ = new array(a);
+ }
+
+ inline value::value(const object& o) : type_(object_type) {
+ object_ = new object(o);
+ }
+
+ inline value::~value() {
+ switch (type_) {
+#define DEINIT(p) case p##type: delete p; break
+ DEINIT(string_);
+ DEINIT(array_);
+ DEINIT(object_);
+#undef DEINIT
+ default: break;
+ }
+ }
+
+ inline value::value(const value& x) : type_(x.type_) {
+ switch (type_) {
+#define INIT(p, v) case p##type: p = v; break
+ INIT(boolean_, x.boolean_);
+ INIT(number_, x.number_);
+ INIT(string_, new std::string(*x.string_));
+ INIT(array_, new array(*x.array_));
+ INIT(object_, new object(*x.object_));
+#undef INIT
+ default: break;
+ }
+ }
+
+ inline value& value::operator=(const value& x) {
+ if (this != &x) {
+ this->~value();
+ new (this) value(x);
+ }
+ return *this;
+ }
+
+#define IS(ctype, jtype) \
+ template <> inline bool value::is<ctype>() const { \
+ return type_ == jtype##_type; \
+ }
+ IS(null, null)
+ IS(bool, boolean)
+ IS(int, number)
+ IS(double, number)
+ IS(std::string, string)
+ IS(array, array)
+ IS(object, object)
+#undef IS
+
+#define GET(ctype, var) \
+ template <> inline const ctype& value::get<ctype>() const { \
+ return var; \
+ } \
+ template <> inline ctype& value::get<ctype>() { \
+ return var; \
+ }
+ GET(bool, boolean_)
+ GET(double, number_)
+ GET(std::string, *string_)
+ GET(array, *array_)
+ GET(object, *object_)
+#undef GET
+
+ inline value::operator bool() const {
+ switch (type_) {
+ case null_type:
+ return false;
+ case boolean_type:
+ return boolean_;
+ case number_type:
+ return number_ != 0;
+ case string_type:
+ return ! string_->empty();
+ default:
+ return true;
+ }
+ }
+
+ inline const value& value::get(size_t idx) const {
+ static value s_null;
+ assert(is<array>());
+ return idx < array_->size() ? (*array_)[idx] : s_null;
+ }
+
+ inline const value& value::get(const std::string& key) const {
+ static value s_null;
+ assert(is<object>());
+ object::const_iterator i = object_->find(key);
+ return i != object_->end() ? i->second : s_null;
+ }
+
+ inline std::string value::to_str() const {
+ switch (type_) {
+ case null_type: return "null";
+ case boolean_type: return boolean_ ? "true" : "false";
+ case number_type: {
+ char buf[256];
+ double tmp;
+ SNPRINTF(buf, sizeof(buf), modf(number_, &tmp) == 0 ? "%.f" : "%f", number_);
+ return buf;
+ }
+ case string_type: return *string_;
+ case array_type: return "array";
+ case object_type: return "object";
+ default: assert(0);
+#ifdef _MSC_VER
+ __assume(0);
+#endif
+ }
+ }
+
+ template <typename Iter> void copy(const std::string& s, Iter oi) {
+ std::copy(s.begin(), s.end(), oi);
+ }
+
+ template <typename Iter> void serialize_str(const std::string& s, Iter oi) {
+ *oi++ = '"';
+ for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
+ switch (*i) {
+#define MAP(val, sym) case val: copy(sym, oi); break
+ MAP('"', "\\\"");
+ MAP('\\', "\\\\");
+ MAP('/', "\\/");
+ MAP('\b', "\\b");
+ MAP('\f', "\\f");
+ MAP('\n', "\\n");
+ MAP('\r', "\\r");
+ MAP('\t', "\\t");
+#undef MAP
+ default:
+ if ((unsigned char)*i < 0x20 || *i == 0x7f) {
+ char buf[7];
+ SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff);
+ copy(buf, buf + 6, oi);
+ } else {
+ *oi++ = *i;
+ }
+ break;
+ }
+ }
+ *oi++ = '"';
+ }
+
+ template <typename Iter> void value::serialize(Iter oi) const {
+ switch (type_) {
+ case string_type:
+ serialize_str(*string_, oi);
+ break;
+ case array_type: {
+ *oi++ = '[';
+ for (array::const_iterator i = array_->begin(); i != array_->end(); ++i) {
+ if (i != array_->begin()) {
+ *oi++ = ',';
+ }
+ i->serialize(oi);
+ }
+ *oi++ = ']';
+ break;
+ }
+ case object_type: {
+ *oi++ = '{';
+ for (object::const_iterator i = object_->begin();
+ i != object_->end();
+ ++i) {
+ if (i != object_->begin()) {
+ *oi++ = ',';
+ }
+ serialize_str(i->first, oi);
+ *oi++ = ':';
+ i->second.serialize(oi);
+ }
+ *oi++ = '}';
+ break;
+ }
+ default:
+ copy(to_str(), oi);
+ break;
+ }
+ }
+
+ inline std::string value::serialize() const {
+ std::string s;
+ serialize(std::back_inserter(s));
+ return s;
+ }
+
+ template <typename Iter> class input {
+ protected:
+ Iter cur_, end_;
+ int last_ch_;
+ bool ungot_;
+ int line_;
+ public:
+ input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {}
+ int getc() {
+ if (ungot_) {
+ ungot_ = false;
+ return last_ch_;
+ }
+ if (cur_ == end_) {
+ last_ch_ = -1;
+ return -1;
+ }
+ if (last_ch_ == '\n') {
+ line_++;
+ }
+ last_ch_ = *cur_++ & 0xff;
+ return last_ch_;
+ }
+ void ungetc() {
+ if (last_ch_ != -1) {
+ assert(! ungot_);
+ ungot_ = true;
+ }
+ }
+ Iter cur() const { return cur_; }
+ int line() const { return line_; }
+ void skip_ws() {
+ while (1) {
+ int ch = getc();
+ if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) {
+ ungetc();
+ break;
+ }
+ }
+ }
+ int expect(int expect) {
+ skip_ws();
+ if (getc() != expect) {
+ ungetc();
+ return false;
+ }
+ return true;
+ }
+ bool match(const std::string& pattern) {
+ for (std::string::const_iterator pi(pattern.begin());
+ pi != pattern.end();
+ ++pi) {
+ if (getc() != *pi) {
+ ungetc();
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
+ template<typename Iter> inline int _parse_quadhex(input<Iter> &in) {
+ int uni_ch = 0, hex;
+ for (int i = 0; i < 4; i++) {
+ if ((hex = in.getc()) == -1) {
+ return -1;
+ }
+ if ('0' <= hex && hex <= '9') {
+ hex -= '0';
+ } else if ('A' <= hex && hex <= 'F') {
+ hex -= 'A' - 0xa;
+ } else if ('a' <= hex && hex <= 'f') {
+ hex -= 'a' - 0xa;
+ } else {
+ in.ungetc();
+ return -1;
+ }
+ uni_ch = uni_ch * 16 + hex;
+ }
+ return uni_ch;
+ }
+
+ template<typename Iter> inline bool _parse_codepoint(std::string& out, input<Iter>& in) {
+ int uni_ch;
+ if ((uni_ch = _parse_quadhex(in)) == -1) {
+ return false;
+ }
+ if (0xd800 <= uni_ch && uni_ch <= 0xdfff) {
+ if (0xdc00 <= uni_ch) {
+ // a second 16-bit of a surrogate pair appeared
+ return false;
+ }
+ // first 16-bit of surrogate pair, get the next one
+ if (in.getc() != '\\' || in.getc() != 'u') {
+ in.ungetc();
+ return false;
+ }
+ int second = _parse_quadhex(in);
+ if (! (0xdc00 <= second && second <= 0xdfff)) {
+ return false;
+ }
+ uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff);
+ uni_ch += 0x10000;
+ }
+ if (uni_ch < 0x80) {
+ out.push_back(uni_ch);
+ } else {
+ if (uni_ch < 0x800) {
+ out.push_back(0xc0 | (uni_ch >> 6));
+ } else {
+ if (uni_ch < 0x10000) {
+ out.push_back(0xe0 | (uni_ch >> 12));
+ } else {
+ out.push_back(0xf0 | (uni_ch >> 18));
+ out.push_back(0x80 | ((uni_ch >> 12) & 0x3f));
+ }
+ out.push_back(0x80 | ((uni_ch >> 6) & 0x3f));
+ }
+ out.push_back(0x80 | (uni_ch & 0x3f));
+ }
+ return true;
+ }
+
+ template<typename Iter> inline bool _parse_string(value& out, input<Iter>& in) {
+ // gcc 4.1 cannot compile if the below two lines are merged into one :-(
+ out = value(string_type, false);
+ std::string& s = out.get<std::string>();
+ while (1) {
+ int ch = in.getc();
+ if (ch < ' ') {
+ in.ungetc();
+ return false;
+ } else if (ch == '"') {
+ return true;
+ } else if (ch == '\\') {
+ if ((ch = in.getc()) == -1) {
+ return false;
+ }
+ switch (ch) {
+#define MAP(sym, val) case sym: s.push_back(val); break
+ MAP('"', '\"');
+ MAP('\\', '\\');
+ MAP('/', '/');
+ MAP('b', '\b');
+ MAP('f', '\f');
+ MAP('n', '\n');
+ MAP('r', '\r');
+ MAP('t', '\t');
+#undef MAP
+ case 'u':
+ if (! _parse_codepoint(s, in)) {
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ } else {
+ s.push_back(ch);
+ }
+ }
+ return false;
+ }
+
+ template <typename Iter> inline bool _parse_array(value& out, input<Iter>& in) {
+ out = value(array_type, false);
+ array& a = out.get<array>();
+ if (in.expect(']')) {
+ return true;
+ }
+ do {
+ a.push_back(value());
+ if (! _parse(a.back(), in)) {
+ return false;
+ }
+ } while (in.expect(','));
+ return in.expect(']');
+ }
+
+ template <typename Iter> inline bool _parse_object(value& out, input<Iter>& in) {
+ out = value(object_type, false);
+ object& o = out.get<object>();
+ if (in.expect('}')) {
+ return true;
+ }
+ do {
+ value key, val;
+ if (in.expect('"')
+ && _parse_string(key, in)
+ && in.expect(':')
+ && _parse(val, in)) {
+ o[key.to_str()] = val;
+ } else {
+ return false;
+ }
+ } while (in.expect(','));
+ return in.expect('}');
+ }
+
+ template <typename Iter> inline bool _parse_number(value& out, input<Iter>& in) {
+ std::string num_str;
+ while (1) {
+ int ch = in.getc();
+ if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == '.'
+ || ch == 'e' || ch == 'E') {
+ num_str.push_back(ch);
+ } else {
+ in.ungetc();
+ break;
+ }
+ }
+ char* endp;
+ out = value(strtod(num_str.c_str(), &endp));
+ return endp == num_str.c_str() + num_str.size();
+ }
+
+ template <typename Iter> inline bool _parse(value& out, input<Iter>& in) {
+ in.skip_ws();
+ int ch = in.getc();
+ switch (ch) {
+#define IS(ch, text, val) case ch: \
+ if (in.match(text)) { \
+ out = val; \
+ return true; \
+ } else { \
+ return false; \
+ }
+ IS('n', "ull", value());
+ IS('f', "alse", value(false));
+ IS('t', "rue", value(true));
+#undef IS
+ case '"':
+ return _parse_string(out, in);
+ case '[':
+ return _parse_array(out, in);
+ case '{':
+ return _parse_object(out, in);
+ default:
+ if (('0' <= ch && ch <= '9') || ch == '-') {
+ in.ungetc();
+ return _parse_number(out, in);
+ }
+ break;
+ }
+ in.ungetc();
+ return false;
+ }
+
+ // obsolete, use the version below
+ template <typename Iter> inline std::string parse(value& out, Iter& pos, const Iter& last) {
+ std::string err;
+ pos = parse(out, pos, last, &err);
+ return err;
+ }
+
+ template <typename Iter> inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) {
+ input<Iter> in(first, last);
+ if (! _parse(out, in) && err != NULL) {
+ char buf[64];
+ SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line());
+ *err = buf;
+ while (1) {
+ int ch = in.getc();
+ if (ch == -1 || ch == '\n') {
+ break;
+ } else if (ch >= ' ') {
+ err->push_back(ch);
+ }
+ }
+ }
+ return in.cur();
+ }
+
+ inline std::string parse(value& out, std::istream& is) {
+ std::string err;
+ parse(out, std::istreambuf_iterator<char>(is.rdbuf()),
+ std::istreambuf_iterator<char>(), &err);
+ return err;
+ }
+
+ template <typename T> struct last_error_t {
+ static std::string s;
+ };
+ template <typename T> std::string last_error_t<T>::s;
+
+ inline void set_last_error(const std::string& s) {
+ last_error_t<bool>::s = s;
+ }
+
+ inline const std::string& get_last_error() {
+ return last_error_t<bool>::s;
+ }
+
+ inline bool operator==(const value& x, const value& y) {
+ if (x.is<null>())
+ return y.is<null>();
+#define PICOJSON_CMP(type) \
+ if (x.is<type>()) \
+ return y.is<type>() && x.get<type>() == y.get<type>()
+ PICOJSON_CMP(bool);
+ PICOJSON_CMP(double);
+ PICOJSON_CMP(std::string);
+ PICOJSON_CMP(array);
+ PICOJSON_CMP(object);
+#undef PICOJSON_CMP
+ assert(0);
+#ifdef _MSC_VER
+ __assume(0);
+#endif
+ return false;
+ }
+
+ inline bool operator!=(const value& x, const value& y) {
+ return ! (x == y);
+ }
+}
+
+inline std::istream& operator>>(std::istream& is, picojson::value& x)
+{
+ picojson::set_last_error(std::string());
+ std::string err = picojson::parse(x, is);
+ if (! err.empty()) {
+ picojson::set_last_error(err);
+ is.setstate(std::ios::failbit);
+ }
+ return is;
+}
+
+inline std::ostream& operator<<(std::ostream& os, const picojson::value& x)
+{
+ x.serialize(std::ostream_iterator<char>(os));
+ return os;
+}
+#ifdef _MSC_VER
+ #pragma warning(pop)
+#endif
+
+#endif
+#ifdef TEST_PICOJSON
+#ifdef _MSC_VER
+ #pragma warning(disable : 4127) // conditional expression is constant
+#endif
+
+using namespace std;
+
+static void plan(int num)
+{
+ printf("1..%d\n", num);
+}
+
+static void ok(bool b, const char* name = "")
+{
+ static int n = 1;
+ printf("%s %d - %s\n", b ? "ok" : "ng", n++, name);
+}
+
+template <typename T> void is(const T& x, const T& y, const char* name = "")
+{
+ if (x == y) {
+ ok(true, name);
+ } else {
+ ok(false, name);
+ }
+}
+
+#include <algorithm>
+
+int main(void)
+{
+ plan(62);
+
+#define TEST(in, type, cmp, serialize_test) { \
+ picojson::value v; \
+ const char* s = in; \
+ string err = picojson::parse(v, s, s + strlen(s)); \
+ ok(err.empty(), in " no error"); \
+ ok(v.is<type>(), in " check type"); \
+ is(v.get<type>(), cmp, in " correct output"); \
+ is(*s, '\0', in " read to eof"); \
+ if (serialize_test) { \
+ is(v.serialize(), string(in), in " serialize"); \
+ } \
+ }
+ TEST("false", bool, false, true);
+ TEST("true", bool, true, true);
+ TEST("90.5", double, 90.5, false);
+ TEST("\"hello\"", string, string("hello"), true);
+ TEST("\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"", string, string("\"\\/\b\f\n\r\t"),
+ true);
+ TEST("\"\\u0061\\u30af\\u30ea\\u30b9\"", string,
+ string("a\xe3\x82\xaf\xe3\x83\xaa\xe3\x82\xb9"), false);
+ TEST("\"\\ud840\\udc0b\"", string, string("\xf0\xa0\x80\x8b"), false);
+#undef TEST
+
+#define TEST(type, expr) { \
+ picojson::value v; \
+ const char *s = expr; \
+ string err = picojson::parse(v, s, s + strlen(s)); \
+ ok(err.empty(), "empty " #type " no error"); \
+ ok(v.is<picojson::type>(), "empty " #type " check type"); \
+ ok(v.get<picojson::type>().empty(), "check " #type " array size"); \
+ }
+ TEST(array, "[]");
+ TEST(object, "{}");
+#undef TEST
+
+ {
+ picojson::value v;
+ const char *s = "[1,true,\"hello\"]";
+ string err = picojson::parse(v, s, s + strlen(s));
+ ok(err.empty(), "array no error");
+ ok(v.is<picojson::array>(), "array check type");
+ is(v.get<picojson::array>().size(), size_t(3), "check array size");
+ ok(v.get(0).is<double>(), "check array[0] type");
+ is(v.get(0).get<double>(), 1.0, "check array[0] value");
+ ok(v.get(1).is<bool>(), "check array[1] type");
+ ok(v.get(1).get<bool>(), "check array[1] value");
+ ok(v.get(2).is<string>(), "check array[2] type");
+ is(v.get(2).get<string>(), string("hello"), "check array[2] value");
+ }
+
+ {
+ picojson::value v;
+ const char *s = "{ \"a\": true }";
+ string err = picojson::parse(v, s, s + strlen(s));
+ ok(err.empty(), "object no error");
+ ok(v.is<picojson::object>(), "object check type");
+ is(v.get<picojson::object>().size(), size_t(1), "check object size");
+ ok(v.get("a").is<bool>(), "check property exists");
+ is(v.get("a").get<bool>(), true,
+ "check property value");
+ is(v.serialize(), string("{\"a\":true}"), "serialize object");
+ }
+
+#define TEST(json, msg) do { \
+ picojson::value v; \
+ const char *s = json; \
+ string err = picojson::parse(v, s, s + strlen(s)); \
+ is(err, string("syntax error at line " msg), msg); \
+ } while (0)
+ TEST("falsoa", "1 near: oa");
+ TEST("{]", "1 near: ]");
+ TEST("\n\bbell", "2 near: bell");
+ TEST("\"abc\nd\"", "1 near: ");
+#undef TEST
+
+ {
+ picojson::value v1, v2;
+ const char *s;
+ string err;
+ s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
+ err = picojson::parse(v1, s, s + strlen(s));
+ s = "{ \"d\": 2.0, \"b\": true, \"a\": [1,2,\"three\"] }";
+ err = picojson::parse(v2, s, s + strlen(s));
+ ok((v1 == v2), "check == operator in deep comparison");
+ }
+
+ {
+ picojson::value v1, v2;
+ const char *s;
+ string err;
+ s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
+ err = picojson::parse(v1, s, s + strlen(s));
+ s = "{ \"d\": 2.0, \"a\": [1,\"three\"], \"b\": true }";
+ err = picojson::parse(v2, s, s + strlen(s));
+ ok((v1 != v2), "check != operator for array in deep comparison");
+ }
+
+ {
+ picojson::value v1, v2;
+ const char *s;
+ string err;
+ s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
+ err = picojson::parse(v1, s, s + strlen(s));
+ s = "{ \"d\": 2.0, \"a\": [1,2,\"three\"], \"b\": false }";
+ err = picojson::parse(v2, s, s + strlen(s));
+ ok((v1 != v2), "check != operator for object in deep comparison");
+ }
+
+ {
+ picojson::value v1, v2;
+ const char *s;
+ string err;
+ s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
+ err = picojson::parse(v1, s, s + strlen(s));
+ picojson::object& o = v1.get<picojson::object>();
+ o.erase("b");
+ picojson::array& a = o["a"].get<picojson::array>();
+ picojson::array::iterator i;
+ i = std::remove(a.begin(), a.end(), picojson::value(std::string("three")));
+ a.erase(i, a.end());
+ s = "{ \"a\": [1,2], \"d\": 2 }";
+ err = picojson::parse(v2, s, s + strlen(s));
+ ok((v1 == v2), "check erase()");
+ }
+
+ ok(picojson::value(3.0).serialize() == "3",
+ "integral number should be serialized as a integer");
+
+ return 0;
+}
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/source/libraries/stats_report.h Tue Jan 22 08:36:23 2019 +0000
@@ -0,0 +1,121 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2018 ARM Limited
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef STATS_REPORT_H
+#define STATS_REPORT
+
+#include "mbed.h"
+
+/**
+ * System Reporting library. Provides runtime information on device:
+ * - CPU sleep, idle, and wake times
+ * - Heap and stack usage
+ * - Thread information
+ * - Static system information
+ */
+class SystemReport {
+ mbed_stats_heap_t heap_stats;
+ mbed_stats_cpu_t cpu_stats;
+ mbed_stats_sys_t sys_stats;
+
+ mbed_stats_thread_t *thread_stats;
+ uint8_t thread_count;
+ uint8_t max_thread_count;
+ uint32_t sample_time_ms;
+
+public:
+ /**
+ * SystemReport - Sample rate in ms is required to handle the CPU percent awake logic
+ */
+ SystemReport(uint32_t sample_rate) : max_thread_count(8), sample_time_ms(sample_rate)
+ {
+ thread_stats = new mbed_stats_thread_t[max_thread_count];
+
+ // Collect the static system information
+ mbed_stats_sys_get(&sys_stats);
+
+ printf("=============================== SYSTEM INFO ================================\r\n");
+ printf("Mbed OS Version: %ld \r\n", sys_stats.os_version);
+ printf("CPU ID: 0x%lx \r\n", sys_stats.cpu_id);
+ printf("Compiler ID: %d \r\n", sys_stats.compiler_id);
+ printf("Compiler Version: %ld \r\n", sys_stats.compiler_version);
+ }
+
+ ~SystemReport(void)
+ {
+ free(thread_stats);
+ }
+
+ /**
+ * Report on each Mbed OS Platform stats API
+ */
+ void report_state(void)
+ {
+ report_cpu_stats();
+ report_heap_stats();
+ report_thread_stats();
+
+ // Clear next line to separate subsequent report logs
+ printf("\r\n");
+ }
+
+ /**
+ * Report CPU idle and awake time in terms of percentage
+ */
+ void report_cpu_stats(void)
+ {
+ static uint64_t prev_idle_time = 0;
+
+ printf("================= CPU STATS =================\r\n");
+
+ // Collect and print cpu stats
+ mbed_stats_cpu_get(&cpu_stats);
+
+ uint64_t diff = (cpu_stats.idle_time - prev_idle_time);
+ uint8_t idle = (diff * 100) / (sample_time_ms * 1000); // usec;
+ uint8_t usage = 100 - ((diff * 100) / (sample_time_ms * 1000)); // usec;;
+ prev_idle_time = cpu_stats.idle_time;
+
+ printf("Idle: %d%% Usage: %d%% \r\n", idle, usage);
+ }
+
+ /**
+ * Report current heap stats. Current heap refers to the current amount of
+ * allocated heap. Max heap refers to the highest amount of heap allocated
+ * since reset.
+ */
+ void report_heap_stats(void)
+ {
+ printf("================ HEAP STATS =================\r\n");
+
+ // Collect and print heap stats
+ mbed_stats_heap_get(&heap_stats);
+
+ printf("Current heap: %lu\r\n", heap_stats.current_size);
+ printf("Max heap size: %lu\r\n", heap_stats.max_size);
+ }
+
+ /**
+ * Report active thread stats
+ */
+ void report_thread_stats(void)
+ {
+ printf("================ THREAD STATS ===============\r\n");
+
+ // Collect and print running thread stats
+ int count = mbed_stats_thread_get_each(thread_stats, max_thread_count);
+
+ for (int i = 0; i < count; i++) {
+ printf("ID: 0x%lx \r\n", thread_stats[i].id);
+ printf("Name: %s \r\n", thread_stats[i].name);
+ printf("State: %ld \r\n", thread_stats[i].state);
+ printf("Priority: %ld \r\n", thread_stats[i].priority);
+ printf("Stack Size: %ld \r\n", thread_stats[i].stack_size);
+ printf("Stack Space: %ld \r\n", thread_stats[i].stack_space);
+ }
+ }
+};
+
+#endif // STATS_REPORT_H
\ No newline at end of file
--- a/source/main.cpp Fri Dec 14 13:15:37 2018 +0000
+++ b/source/main.cpp Tue Jan 22 08:36:23 2019 +0000
@@ -1,71 +1,217 @@
-/* mbed Microcontroller Library
- * Copyright (c) 2006-2015 ARM Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+#define END_OF_JSON 0xFE
-#include <events/mbed_events.h>
-#include <mbed.h>
+#include "mbed.h"
+#include "picojson.h"
+#include "stats_report.h"
+
+/* Librerías para BLE - Servicio GATT */
#include "ble/BLE.h"
#include "ble/Gap.h"
-#include "ble/services/HeartRateService.h"
+#include "ble/DiscoveredCharacteristic.h"
+#include "ble/DiscoveredService.h"
+
+DiscoveredCharacteristic testServiceptr;
+
+bool serviceDiscovered = false;
+
+DigitalOut led3Test(LED3);
+DigitalOut led4BLE(LED4);
+Serial pcSerial(USBTX, USBRX); // Abrimos conexión serial con el puerto USB
+
+EventQueue eventQueue;
-DigitalOut led1(LED1, 1);
+Thread threadLED(osPriorityAboveNormal1, 400);
+//Thread threadSerial(osPriorityAboveNormal2, 2000);
+Thread threadBLE(osPriorityRealtime3, 2000);
+
+int getNum(char ch)
+{
+ int num=0;
+ if(ch>='0' && ch<='9')
+ {
+ num=ch-0x30;
+ }
+ else
+ {
+ switch(ch)
+ {
+ case 'A': case 'a': num=10; break;
+ case 'B': case 'b': num=11; break;
+ case 'C': case 'c': num=12; break;
+ case 'D': case 'd': num=13; break;
+ case 'E': case 'e': num=14; break;
+ case 'F': case 'f': num=15; break;
+ default: num=0;
+ }
+ }
+ return num;
+}
+
+//function : hex2int
+//this function will return integer value against
+//hexValue - which is in string format
+
+unsigned int hex2int(unsigned char hex[])
+{
+ unsigned int x=0;
+ x=(getNum(hex[0]))*16+(getNum(hex[1]));
+ return x;
+
+}
+
+/**
+ * Tarea encargada de parpadear un LED continuamente
+ */
+void blinkLED3() {
+ while(true) {
+ led3Test = !led3Test;
+ wait(0.2);
+ }
+}
+
+/**
+ * Método encargado de enviar un string por el puerto serie char a char
+ */
+void sendCharArrayToSerial(char const *array, Serial *serial) {
+ int i = 0;
+ while(array[i] != '\0') {
+ serial->putc(array[i]);
+ i++;
+ }
+ serial->putc('\0');
+}
-const static char DEVICE_NAME[] = "HRM";
-static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE};
+/**
+ * Tarea encragada de enviar JSONs por el puerto serie
+ */
+void sendJsonOverSerial() {
+ /* Contruimos el objeto JSON */
+ picojson::object worker;
+ picojson::object vehicle;
+ picojson::object device;
+ picojson::object event;
+ picojson::object data;
+
+ string tmpValue = "1234";
+ char tmp[1024];
+ string str;
+ char final = END_OF_JSON; // Caracter que indica el final del JSON
+
+ while(true) {
+ worker["idDevice"] = picojson::value(tmpValue);
+ tmpValue = "12-12-2019";
+ worker["tsLastSeen"] = picojson::value(tmpValue);
+ tmpValue = "Baby Driver";
+ worker["role"] = picojson::value(tmpValue);
+ tmpValue = "12345";
+ worker["idVehicle"] = picojson::value(tmpValue);
+
+ tmpValue = "123456";
+ vehicle["idDevice"] = picojson::value(tmpValue);
+ tmpValue = "18-12-2019";
+ vehicle["tsLastSeen"] = picojson::value(tmpValue);
+
+ tmpValue = "11111";
+ device["idDevice"] = picojson::value(tmpValue);
+ device["battLevel"] = picojson::value(45.0);
+ tmpValue = "Pulsera";
+ device["deviceType"] = picojson::value(tmpValue);
+
+ tmpValue = "256745";
+ event["idEvent"] = picojson::value(tmpValue);
+ event["hazardousDevice"] = picojson::value(false);
+ event["affectedDevice"] = picojson::value(true);
+ tmpValue = "Critical";
+ event["eventType"] = picojson::value(tmpValue);
+ tmpValue = "19-12-2018";
+ event["tsEvent"] = picojson::value(tmpValue);
+
+ data["worker"] = picojson::value(worker);
+ data["vehicle"] = picojson::value(vehicle);
+ data["device"] = picojson::value(device);
+ data["event"] = picojson::value(event);
+
+ str = picojson::value(data).serialize();
+
+ // Convertimos el string a char *
+ strncpy(tmp, str.c_str(), sizeof(tmp));
+ strncat(tmp, &final, sizeof(final)); // Añadimos el caracter al final
+ tmp[sizeof(tmp) - 1] = 0;
-static uint8_t hrmCounter = 100; // init HRM to 100bps
-static HeartRateService *hrServicePtr;
+ //sendCharArrayToSerial(tmp, &pcSerial);
+
+ wait(0.5);
+ }
+}
+
+void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) {
+ if (params->peerAddr[0] != 0x8E) return;
+ printf("adv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, isScanResponse %u, AdvertisementType %u\r\n",
+ params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0],
+ params->rssi, params->isScanResponse, params->type);
+
+ BLE::Instance().gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL);
+}
-static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE);
+void serviceDiscoveryCallback(const DiscoveredService *service) {
+ if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
+ printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle());
+ } else {
+ printf("S UUID-");
+ const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
+ for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
+ printf("%02x", longUUIDBytes[i]);
+ }
+ printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
+ }
+}
+
+void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) {
+ printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
+ if (characteristicP->getUUID().getShortUUID() == 0xa001) { /* !ALERT! Alter this filter to suit your device. */
+ testServiceptr = *characteristicP;
+ serviceDiscovered = true;
+ }
+}
+
+void discoveryTerminationCallback(Gap::Handle_t connectionHandle) {
+ printf("terminated SD for handle %u\r\n", connectionHandle);
+}
+
+void connectionCallback(const Gap::ConnectionCallbackParams_t *params) {
+ if (params->role == Gap::CENTRAL) {
+ BLE::Instance().gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
+ BLE::Instance().gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, 0xA000, 0xA001);
+ }
+}
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
- BLE::Instance().gap().startAdvertising(); // restart advertising
+ /* Si se desconecta el dispositivo, volvemos a entrar en estado Advertising*/
+ (void) params;
+ printf("Desconectado. Se comienza la fase de escaneo de nuevo\n\r");
+ serviceDiscovered = false;
+ BLE::Instance().gap().startScan(advertisementCallback);
}
-void updateSensorValue() {
- // Do blocking calls or whatever is necessary for sensor polling.
- // In our case, we simply update the HRM measurement.
- hrmCounter++;
-
- // 100 <= HRM bps <=175
- if (hrmCounter == 175) {
- hrmCounter = 100;
- }
-
- hrServicePtr->updateHeartRate(hrmCounter);
-}
-
-void periodicCallback(void)
-{
- led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
-
- if (BLE::Instance().getGapState().connected) {
- eventQueue.call(updateSensorValue);
+void onDataReadClientCallback(const GattReadCallbackParams *response) {
+ if (response->handle == testServiceptr.getValueHandle()) {
+ printf("onDataReadClientCallback: handle %u, offset %u, len %u\r\n", response->handle, response->offset, response->len);
+ for (unsigned index = 0; index < response->len; index++) {
+ printf("[%02x]", response->data[index]);
+ }
+ printf("\r\n");
}
}
-void onBleInitError(BLE &ble, ble_error_t error)
-{
- (void)ble;
- (void)error;
- /* Initialization error handling should go here */
+/**
+ * Esta función se llama si ha habido algún error en el proceso de inicialización del BLE
+ */
+void onBleInitError(BLE &ble, ble_error_t error) {
+ printf("Ha ocurrido un error al inicializar la configuracion del BLE\n");
}
-void printMacAddress()
-{
+void printMacAddress() {
/* Print out device MAC address to the console*/
Gap::AddressType_t addr_type;
Gap::Address_t address;
@@ -77,51 +223,66 @@
printf("%02x\r\n", address[0]);
}
+/**
+ * Callback triggered when the ble initialization process has finished
+ */
void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
{
BLE& ble = params->ble;
ble_error_t error = params->error;
if (error != BLE_ERROR_NONE) {
+ /* In case of error, forward the error handling to onBleInitError */
onBleInitError(ble, error);
return;
}
- if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
+ /* Ensure that it is the default instance of BLE */
+ if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
return;
}
-
+
+ ble.gap().onConnection(connectionCallback);
ble.gap().onDisconnection(disconnectionCallback);
- /* Setup primary service. */
- hrServicePtr = new HeartRateService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
+ ble.gattClient().onDataRead(onDataReadClientCallback);
- /* Setup advertising. */
- ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
- ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
- ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
- ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
- ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
- ble.gap().setAdvertisingInterval(1000); /* 1000ms */
- ble.gap().startAdvertising();
-
- printMacAddress();
+ ble.gap().setScanParams(500, 400);
+ ble.gap().startScan(advertisementCallback);
+
+ //printMacAddress();
}
void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
BLE &ble = BLE::Instance();
eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
+}
+
+void readVoltageValue() {
+ BLE &ble = BLE::Instance();
+ if (serviceDiscovered && !ble.gattClient().isServiceDiscoveryActive()) {
+ testServiceptr.read();
+ }
}
-int main()
-{
- eventQueue.call_every(500, periodicCallback);
-
+void BLEServiceManagment() {
+ eventQueue.call_every(2000, readVoltageValue);
+
BLE &ble = BLE::Instance();
- ble.onEventsToProcess(scheduleBleEventsProcessing);
+ ble.onEventsToProcess(scheduleBleEventsProcessing);
ble.init(bleInitComplete);
-
+
eventQueue.dispatch_forever();
+}
+int main() {
+ threadLED.start(blinkLED3);
+ threadBLE.start(BLEServiceManagment);
+ //threadSerial.start(sendJsonOverSerial);
+
+ threadLED.join();
+ threadBLE.join();
+ //threadSerial.join();
+
return 0;
-}
+}
\ No newline at end of file