error: expected identifier before '_Bool' - pebble-sdk

I previously had the following code when dealing with my sync tuple:
static void sync_tuple_changed_callback(const uint32_t key, const Tuple* new_tuple, const Tuple* old_tuple, void* context) {
persist_write_bool(key,new_tuple->value->bool);
}
However, I just tried building this (in Cloud Pebble), and got the error:
../src/main.c: In function 'sync_tuple_changed_callback':
../src/main.c:25:44: error: expected identifier before '_Bool'
What's going on?

There is no bool member of the value union - your best bet is to use the uint8 member instead, passing 1 for true and 0 for false:
static void sync_tuple_changed_callback(const uint32_t key, const Tuple* new_tuple, const Tuple* old_tuple, void* context) {
persist_write_bool(key,new_tuple->value->uint8 != 0);
}

Related

Thingsboard Arduino Client Library issues

So I've been working on modifying the thingsboard arduino library to support device provisioning. I've duplicated/renamed/modified a handful of functions in the library to support pointing to the correct topics, and added the supporting code in my main application to make use of them. However, I am now getting a compiler error in a section of the library code I did not touch. I'm hoping someone can point out what I goofed up, as it appears like it should be a fairly simple fix if I can find it.
This is the bit of code giving me the error-
inline Telemetry(const char *key, T val)
:m_type(TYPE_INT), m_key(key), m_value() { m_value.integer = val; }
Here is the error -
In file included from src\main.cpp:12:0:
.pio\libdeps\win\ThingsBoard\src/ThingsBoard.h: In instantiation of 'Telemetry::Telemetry(const char*, T) [with T = String; <template-parameter-1-2> = ArduinoJson6172_91::enable_if<false, void>]':
src\main.cpp:514:33: required from here
.pio\libdeps\win\ThingsBoard\src/ThingsBoard.h:46:64: error: cannot convert 'String' to 'int' in assignment
:m_type(TYPE_INT), m_key(key), m_value() { m_value.integer = val; }
Here's the bulk of what I added to my main code to handle device registration.
RPC_Response processDeviceRegistration(const RPC_Data &data)
{
Serial.println("Received the device registration response");
if(data["status"]=="SUCCESS"){
String credential = data["credentialsValue"];
EEPROM.write(10, sizeof(credential));
EEPROM.writeString(20, (String)credential);
dr.DR_Unsubscribe();
return RPC_Response("registration response", true);
}
else{
Serial.println("Device registration failed");
return RPC_Response("registration response", false);
}
}
const size_t callbacks_size = 2;
RPC_Callback callbacks[callbacks_size] = {
{ "device_registration", processDeviceRegistration }
};
void reinitialize()
{
if (!dr.RPC_Subscribe(callbacks, 1)) {
Serial.println("Failed to subscribe for RPC");
return;
}
dr.loop();
String IMEI = modem.getIMEI();
const int data_items = 3;
Telemetry data[data_items] = {
Telemetry("deviceName", IMEI),
Telemetry("provisionDeviceKey", provision_device_key),
Telemetry("provisionDeviceSecret", provision_device_secret),
};
if (!dr.sendDR(data, data_items)){
Serial.println("Device registration send failed");
}
If it would be helpful, I can fork and upload the full library code and post a link to my github.
----- Edit -----
Upon further investigation, it appears the template for the Telemetry class is detecting the IMEI variable as an integer rather than a string and trying to convert it for some reason. I have no idea why, or how to fix it. Any suggestions would be greatly appreciated.
Well then, helps if I take a few minutes to actually understand the code I didn't write that is giving me grief. There was no handler in the Telemetry constructor for a character array or string type variable. Added that and now everything is working :)
Full Telemetry constructor below -
inline Telemetry()
:m_type(TYPE_NONE), m_key(NULL), m_value() { }
// Constructs telemetry record from integer value.
// EnableIf trick is required to overcome ambiguous float/integer conversion
template<
typename T,
typename = ARDUINOJSON_NAMESPACE::enable_if<ARDUINOJSON_NAMESPACE::is_integral<T>::value>
>
inline Telemetry(const char *key, T val)
:m_type(TYPE_INT), m_key(key), m_value() { m_value.integer = val; }
// Constructs telemetry record from boolean value.
inline Telemetry(const char *key, bool val)
:m_type(TYPE_BOOL), m_key(key), m_value() { m_value.boolean = val; }
// Constructs telemetry record from float value.
inline Telemetry(const char *key, float val)
:m_type(TYPE_REAL), m_key(key), m_value() { m_value.real = val; }
// Constructs telemetry record from string value.
inline Telemetry(const char *key, const char *val)
:m_type(TYPE_STR), m_key(key), m_value() { m_value.str = val; }
// Constructs telemetry record from string value.
inline Telemetry(const char *key, char *val)
:m_type(TYPE_STR), m_key(key), m_value() { m_value.str = val; }

Using valgrind - "Invalid read of size 1" for strlen

I'm trying to write code that sets the name of a Student object to a new name, but I'm coming across memory leak errors when creating a character array. I assume it has to do with /0 at the end of the array and isn't terminating properly, but I don't know how to properly fix this. Thanks for the help.
#include "student.h"
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
Student::Student(const char * const name, int perm) {
this->setName(name);
this->setPerm(perm);
}
int Student::getPerm() const {
return this->perm;
}
const char * const Student::getName() const {
return this->name;
}
void Student::setPerm(const int perm) {
this->perm = perm;
}
void Student::setName(const char * const newName) {
this->name = new char[strlen(newName)+1];
// this->name[srtlen(newName)+1] = '/0'; <---- My suggested fix, but doesn't work
strcpy(this->name,newName);
}
Student::Student(const Student &orig) {
this->setName(orig.getName());
this->setPerm(orig.getPerm());
}
Student::~Student() {
delete this->name;
this->perm = 0;
}
This is the valgrind error:
==13814== Invalid read of size 1
==13814== at 0x4C2BA12: strlen (vg_replace_strmem.c:454)
==13814== by 0x4F56FD6: UnknownInlinedFun (char_traits.h:267)
==13814== by 0x4F56FD6: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (basic_string.h:456)
==13814== by 0x401ED8: Student::toString[abi:cxx11]() const (student.cpp:64)
==13814== by 0x401A46: main (testStudent00.cpp:14)
==13814== Address 0x5302e8 is not stack'd, malloc'd or (recently) free'd
==13814==
Your assumption that you needed to add the 0 terminator is wrong, strcpy() will do that for you. Your attempt of doing so adds the 0 terminator one byte past the space you allocated (remember, array indexes start at zero), and the syntax is also wrong, you would need to do:
this->name[strlen(newName)] = '\0';
However, to fix your memory leak You need to delete the previous string, like
void Student::setName(const char * const newName)
{
delete [] this->name;
this->name = new char[strlen(newName)+1];
strcpy(this->name,newName);
}
Student::Student(const Student &orig) :
name(0) {
this->setName(orig.getName());
this->setPerm(orig.getPerm());
}
Student::~Student() {
delete [] this->name;
this->perm = 0;
}
Now, for this to work, you also need to fix your constructor and copy constructor to initialize the name member, so it isn't an uninitialized pointer for the first call to the setName() function, and you need to add an assignment operator too, so you can properly handle assignments.
Student::Student(const char * const name, int perm) :
name(0)
{
this->setName(name);
this->setPerm(perm);
}
Student &operator=(const Student &orig) {
this->setName(orig.getName());
this->setPerm(orig.getPerm());
}
Also, consider using std::string instead of your current low level way of handling strings, that way you don't need to even implement a copy constructor, assignment operator and destructor for this class, nor deal with correctly managing memory.

How to get human-readable event type from QEvent?

I want to debug event handling code and would like to convert QEvent::Type enum's value to a human-readable string. QEvent has a Q_GADGET macro, so presumably there's a way of pulling that off?
Recent versions of Qt do the right thing when outputting events to the debug stream, so the below isn't neccessary. If you get an error similar to warning C4273: 'operator <<' : inconsistent dll linkage, it means that your version of Qt already supports this without need for the code below.
The Q_GADGET macro adds a QMetaObject staticMetaObject member to the class. The static metaobject's definition is generated by moc, and it - in the case of QEvent - contains the enumeration information.
Below is an example of how to leverage that to give a more reasonable QDebug output of events.
#include <QEvent>
#include <QMetaEnum>
#include <QDebug>
/// Gives human-readable event type information.
QDebug operator<<(QDebug str, const QEvent * ev) {
static int eventEnumIndex = QEvent::staticMetaObject
.indexOfEnumerator("Type");
str << "QEvent";
if (ev) {
QString name = QEvent::staticMetaObject
.enumerator(eventEnumIndex).valueToKey(ev->type());
if (!name.isEmpty()) str << name; else str << ev->type();
} else {
str << (void*)ev;
}
return str.maybeSpace();
}
Use example:
void MyObject::event(QEvent* ev) {
qDebug() << "handling an event" << ev;
}
Q_GADGET and Q_ENUM can be combined to get the following template:
template<typename EnumType>
QString ToString(const EnumType& enumValue)
{
const char* enumName = qt_getEnumName(enumValue);
const QMetaObject* metaObject = qt_getEnumMetaObject(enumValue);
if (metaObject)
{
const int enumIndex = metaObject->indexOfEnumerator(enumName);
return QString("%1::%2::%3").arg(metaObject->className(), enumName, metaObject->enumerator(enumIndex).valueToKey(enumValue));
}
return QString("%1::%2").arg(enumName).arg(static_cast<int>(enumValue));
}
Example:
void MyObject::event(QEvent* ev)
{
qDebug() << ToString(ev->type());
}

How to find the corresponding key value from the string inserted into a QMap?

I have the following data structure.
QMap<int,QString> map;
map.insert(0x01,"HELLO");
map.insert(0x02,"FELLOW");
map.insert(0x83,"NESTLE");
map.insert(0x044,"KITKAT");
QString str="NESTLE";
My requirement is to retrieve the value -0x83 when the string - NESTLE is passed.
Basically, based on str value, I want to get the corresponding key value i.e. 0x83 in this example. How can I do so?
I would do this:
[..]
QString str = "NESTLE";
int key = getKey(map, str); // should return 0x83 in your example.
[..]
int getKey(const QMap &map, const QString &value)
{
foreach (QString v, map) {
if (v == value)
return map.key(value);
}
return -1;
}
UPDATE:
Or the key could be simply found, by:
int key = map.key("NESTLE");
There are two approaches, depending on how many items are in the map.
If the map has few items (say <20), you can search for the key using map.key(). This performs a linear search over all items, and thus will perform badly for large maps due to O(N) complexity of such a search.
Alternatively, you can implement a bidirectional map. Shown below is a very trivial variant that only works for distinct T1 and T2. Note that there are no non-const index operators, since both maps would need to be modified. This would need a wrapper class.
template <typename T1, typename T2> class BiMap {
QMap<T1, T2> m_map1;
QMap<T2, T1> m_map2;
public:
typedef QMap<T1, T2>::iterator iterator1;
typedef QMap<T1, T2>::const_iterator const_iterator1;
typedef QMap<T2, T1>::iterator iterator2;
typedef QMap<T2, T1>::const_iterator const_iterator2;
iterator1 insert(const T1 & key, const T2 & value) {
m_map2.insert(value, key);
return m_map1.insert(key, value);
}
iterator2 insert(const T2 & key, const T1 & value) {
m_map1.insert(value, key);
return m_map2.insert(key, value);
}
const T1 & operator[](const T1 & key) const {
return m_map1[key];
}
const T2 & operator[](const T2 & key) const {
return m_map2[key];
}
};
BiMap<int,QString> map;
map.insert(0x01, "HELLO");
map.insert(0x02, "FELLOW");
map.insert(0x83, "NESTLE");
map.insert(0x044, "KITKAT");
int key = map["NESTLE"];
C++ algorithm should work fine:
#include <algorithm>
#include <iostream>
QMap<int,QString> map;
map.insert(0x01,"HELLO");
map.insert(0x02,"FELLOW");
map.insert(0x83,"NESTLE");
map.insert(0x044,"KITKAT");
QString str="NESTLE";
auto it = std::find_if(map.begin(), map.end(),
[&str](const QString &p){ return p == str; });
if(it != map.end())
std::cout << "0x" << std::hex << it.key();

assignment from incompatible pointer type (struct) c

for the struct
typedef struct Recording_Settings recording_settings;
struct Recording_Settings
{
gchar *profile;
gchar *destination;
};
recording_settings rec_settings;
I get a warning when I try to do this
static void profile_combo_change_cb(GtkComboBox *combo, gpointer userdata)
{
GtkTreeIter iter;
GtkTreeModel *model;
/* Grab the encoding profile choosen */
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter)) {
gchar *media_type;
gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &media_type, -1);
rec_settings.profile = rb_gst_get_encoding_profile(media_type); // Warning: assignment from incompatible pointer type
g_free (media_type);
}
}
Am I misunderstanding or missing something?
Thanks.
The type of rb_gst_get_encoding_profile seems to be
GstEncodingProfile *rb_gst_get_encoding_profile (const char *media_type);
but you assign its return value to a gchar *.
GstEncodingProfile is a struct type, as far as I can determine (typedef struct _GstEncodingProfile GstEncodingProfile;), and gchar is probably a typedef for a character type (most likely typedef char gchar; from glib). So the types would be incompatible.

Resources