after posting this topic:
viewtopic.php?f=2&t=10764
I also wanted to try a different approach: using the dictionary directly, and convert it to JSON by myself, see code below. This works, but not in all cases. As soon as I append an element to the dictionary in MicroPython, I get a core panic when I try to access this newly added element. There is no problem accessing the element before it. A check for "is string" before retrieving a string from it doesn't prevent the core panic, probably because the access to this element already is the problem.
So what's the correct way to work with this dictionary then? Is it even possible to use it from a different thread?
Thanks in advance for help and suggestions!
Used hardware: WiPy v3.0 (containing an ESP32D0WDQ6 (revision 1))
Used framework: Pycom MicroPython 1.20.2.r4 [v1.20.1.r2-363-ga37510c0-dirty] on 2021-06-30;
Used ESP-IDF: v3.3.x
MicroPython Version: (name='micropython', version=(1, 11, 0))
C part
Code: Select all
static mp_obj_t ConfigDict;
cJSON* CreateJsonElement(mp_obj_t Element, char* Name, cJSON* Json)
{
printf("creating item for type %s\n", mp_obj_get_type_str(Element));
cJSON* item = NULL;
if (mp_obj_is_int(Element) || mp_obj_is_float(Element))
{
//cJSON_AddNumberToObject(Json, Name, mp_obj_get_float(Element));
item = cJSON_CreateNumber(mp_obj_get_float(Element));
printf("created number with value %f\n", mp_obj_get_float(Element));
}
else if (mp_obj_is_str(Element))
{
//cJSON_AddStringToObject(Json, Name, mp_obj_str_get_str(Element));
item = cJSON_CreateString(mp_obj_str_get_str(Element));
printf("created string with value %s\n", mp_obj_str_get_str(Element));
}
else if (strcmp("dict", mp_obj_get_type_str(Element)) == 0)
{
//ret = cJSON_AddObjectToObject(Json, Name);
item = cJSON_CreateObject();
printf("created empty object with following dict for key %s\n", Name);
}
else if (strcmp("list", mp_obj_get_type_str(Element)) == 0)
{
//get list items
mp_obj_t* listElements;
size_t listLen = 0;
mp_obj_list_get(Element, &listLen, &listElements);
//cJSON* array = cJSON_AddArrayToObject(Json, Name);
item = cJSON_CreateArray();
printf("created array\n");
//iterate over items, that now should only contain base types
for (int i = 0; i < listLen; i++)
{
printf("adding item of type %s to array\n", mp_obj_get_type_str(listElements[i]));
cJSON_AddItemToArray(item, CreateJsonElement(listElements[i],"",item));
}
}
if (item == NULL)
{
printf("could not create item, because type is unknown or an error happened during creation\n");
}
UBaseType_t uxHighWaterMark = 0;
uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL);
printf("JSON: high water mark stack: %"PRIu16"\n", uxHighWaterMark);
return item;
}
static uint8_t dictLevel = 0;
void DictToJsonRecursive(mp_obj_t DictOrList, cJSON* Json)
{
if (Json == NULL)
{
Json = cJSON_CreateObject();
}
printf("starting to convert element of type %s to JSON\n", mp_obj_get_type_str(DictOrList));
mp_map_t* map = NULL;
if (strcmp("dict", mp_obj_get_type_str(DictOrList)) == 0)
{
map = mp_obj_dict_get_map(DictOrList);
}
else
{
printf("object is no dict\n");
}
cJSON* item= NULL;
if (map != NULL)
{
printf("elements in map: %"PRIu32"\n", map->used);
for (int i = 0; i < map->used; i++)
{
printf("creating JSON item for key ");
if (mp_obj_is_str(map->table[i].key))
{
printf("%s\n", mp_obj_str_get_str(map->table[i].key));
}
else
{
printf("KEY ERROR for element %d\n", i);
}
item = CreateJsonElement(map->table[i].value, mp_obj_str_get_str(map->table[i].key), Json);
printf("adding new item to object\n");
cJSON_AddItemToObject(Json, mp_obj_str_get_str(map->table[i].key), item);
if (strcmp("dict", mp_obj_get_type_str(map->table[i].value)) == 0)
{
dictLevel++;
printf("going into nested dict level %d\n", dictLevel);
DictToJsonRecursive(map->table[i].value, item);
printf("coming back from dict level %d, going to level %d\n", dictLevel, dictLevel - 1);
dictLevel--;
}
printf("processing next item of current dict on level %d\n", dictLevel);
}
}
else
{
printf("ERROR: cannot get map from dictionary\n");
}
}
#define JSONBUFFLEN (6 * 1024)
static char jsonBuff[JSONBUFFLEN] = {0};
void TestTask(void* PvParameters)
{
C_CallBackExecutionTaskData* data = (C_CallBackExecutionTaskData*) PvParameters;
// init semaphores
printf("TestTask: creating semaphores\n");
data->processed = xSemaphoreCreateBinary(); //semaphore is locked in initial state
data->request = xSemaphoreCreateBinary(); //semaphore is locked in initial state
printf("TestTask: starting loop\n");
while (true)
{
// 1. Wait for new processing request (semaphore released)
printf("TestTask: waiting for work\n");
xSemaphoreTake(data->request, portMAX_DELAY);
uint32_t coreId = xPortGetCoreID();
printf("TestTask: processing on core %"PRIu32"\n",coreId);
// 2. do the work
cJSON* configJson = cJSON_CreateObject();
DictToJsonRecursive(ConfigDict, configJson);
cJSON_PrintPreallocated(configJson, &jsonBuff[0], JSONBUFFLEN, 0);
printf("cJSON export of dict: %s\n", &jsonBuff[0]);
cJSON_Delete(configJson);
printf("TestTask: work done\n");
// 3. release process ready lock
printf("TestTask: signalling processing finished\n");
xSemaphoreGive(data->processed);
}
}
void TestTaskExecution(void)
{
// release task that processes the callback
printf("TestTaskExecution: releasing test task\n");
xSemaphoreGive(callBackExecutionTaskData.request);
// wait for the process to be finished
printf("TestTaskExecution: waiting for test task to finish\n");
BaseType_t semRet = xSemaphoreTake(callBackExecutionTaskData.processed, 10000 / portTICK_PERIOD_MS); //wait for the response 10s at max
if (semRet == pdFALSE)
{
printf("TestTaskExecution: task timed out\n");
}
else
{
printf("TestTaskExecution: task has returned\n");
}
}
STATIC mp_obj_t DictTestTask(void)
{
printf("DictTestThread: requesting TestTask execution\n");
TestTaskExecution();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(DictTestTask_obj, DictTestTask);
STATIC mp_obj_t TestTaskStart(void)
{
// pin task to run on core 1, the same as µPython
printf("creating test task\n");
xTaskCreatePinnedToCore(TestTask, "TestTask", 1024 * 17, &callBackExecutionTaskData, tskIDLE_PRIORITY + 2, NULL, 1);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(TestTaskStart_obj, TestTaskStart);
STATIC mp_obj_t SetDict(mp_obj_t NewDict)
{
ConfigDict = NewDict;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(SetDict_obj, SetDict);
Code: Select all
testDict = {"key_string":"value1","key_dict":{"keyindict2_int":1,"keyindict2_array":["array1","array2"], "keyindict2_float1": 3.4}}
def PrepareDictTest():
print("Python: saving dict to C")
websrv.SetDict(testDict)
print("Python: starting dict test task in C module")
websrv.TestTaskStart()
def PerformDictTest():
print("Python: performing dict test called from uPython, processed in thread")
websrv.DictTestTask()
def PerformDictChangeTest():
global testDict
global counter
key = "key_string"
testDict[key] = "value{}".format(counter)
counter = counter + 1
print("Python: changed test dictionary to:")
print(testDict)
print("Python: performing dict test called from uPython, processed in thread")
websrv.DictTestTask()
def PerformDictAppendTest():
global testDict
global counter
key = "test{}".format(counter)
testDict[key] = "value{}".format(counter)
counter = counter + 1
print("Python: appended test dictionary to:")
print(testDict)
print("Python: performing dict test called from uPython, processed in thread")
websrv.DictTestTask()