Sfoglia il codice sorgente

Update JSON, README, and GPIO

jblanked 1 anno fa
parent
commit
a4ab1ac418
4 ha cambiato i file con 745 aggiunte e 443 eliminazioni
  1. 5 0
      README.md
  2. 1 79
      flip_library_callback.h
  3. 0 4
      flipper_http.h
  4. 739 360
      jsmn.h

+ 5 - 0
README.md

@@ -4,6 +4,11 @@ The app includes a **dictionary**, **random facts**, and additional functionalit
 
 
 FlipLibrary uses the FlipperHTTP flash for the WiFi Devboard, first introduced in the WebCrawler app: https://github.com/jblanked/WebCrawler-FlipperZero/tree/main/assets/FlipperHTTP
 FlipLibrary uses the FlipperHTTP flash for the WiFi Devboard, first introduced in the WebCrawler app: https://github.com/jblanked/WebCrawler-FlipperZero/tree/main/assets/FlipperHTTP
 
 
+
+## Requirements
+- WiFi Dev Board for Flipper Zero with FlipperHTTP Flash: https://github.com/jblanked/WebCrawler-FlipperZero/tree/main/assets/FlipperHTTP
+- WiFi Access Point
+
 ## Features
 ## Features
 - **Dictionary**: Look up definitions of words directly on your Flipper Zero. Simply enter a word, and the app will provide its definition, making it easy to learn new vocabulary or clarify meaning.
 - **Dictionary**: Look up definitions of words directly on your Flipper Zero. Simply enter a word, and the app will provide its definition, making it easy to learn new vocabulary or clarify meaning.
 - **Random Facts**: Discover interesting and fun facts to share with friends or expand your general knowledge. The app offers various categories of facts, such as facts about cats or completely random trivia.
 - **Random Facts**: Discover interesting and fun facts to share with friends or expand your general knowledge. The app offers various categories of facts, such as facts about cats or completely random trivia.

+ 1 - 79
flip_library_callback.h

@@ -9,85 +9,6 @@ static FlipLibraryApp *app_instance = NULL;
 
 
 #define MAX_TOKENS 512 // Adjust based on expected JSON size
 #define MAX_TOKENS 512 // Adjust based on expected JSON size
 
 
-// Helper function to compare JSON keys
-int jsoneq(const char *json, jsmntok_t *tok, const char *s)
-{
-    if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start &&
-        strncmp(json + tok->start, s, tok->end - tok->start) == 0)
-    {
-        return 0;
-    }
-    return -1;
-}
-
-// return the value of the key in the JSON data
-// works for the first level of the JSON data
-char *get_json_value(char *key, char *json_data, uint32_t max_tokens)
-{
-    // Parse the JSON feed
-    if (json_data != NULL)
-    {
-        jsmn_parser parser;
-        jsmn_init(&parser);
-
-        // Allocate tokens array on the heap
-        jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * max_tokens);
-        if (tokens == NULL)
-        {
-            FURI_LOG_E(TAG, "Failed to allocate memory for JSON tokens.");
-            return NULL;
-        }
-
-        int ret = jsmn_parse(&parser, json_data, strlen(json_data), tokens, max_tokens);
-        if (ret < 0)
-        {
-            // Handle parsing errors
-            FURI_LOG_E(TAG, "Failed to parse JSON: %d", ret);
-            free(tokens);
-            return NULL;
-        }
-
-        // Ensure that the root element is an object
-        if (ret < 1 || tokens[0].type != JSMN_OBJECT)
-        {
-            FURI_LOG_E(TAG, "Root element is not an object.");
-            free(tokens);
-            return NULL;
-        }
-
-        // Loop through the tokens to find the key
-        for (int i = 1; i < ret; i++)
-        {
-            if (jsoneq(json_data, &tokens[i], key) == 0)
-            {
-                // We found the key. Now, return the associated value.
-                int length = tokens[i + 1].end - tokens[i + 1].start;
-                char *value = malloc(length + 1);
-                if (value == NULL)
-                {
-                    FURI_LOG_E(TAG, "Failed to allocate memory for value.");
-                    free(tokens);
-                    return NULL;
-                }
-                strncpy(value, json_data + tokens[i + 1].start, length);
-                value[length] = '\0'; // Null-terminate the string
-
-                free(tokens); // Free the token array
-                return value; // Return the extracted value
-            }
-        }
-
-        // Free the token array if key was not found
-        free(tokens);
-    }
-    else
-    {
-        FURI_LOG_E(TAG, "JSON data is NULL");
-    }
-    FURI_LOG_E(TAG, "Failed to find the key in the JSON.");
-    return NULL; // Return NULL if something goes wrong
-}
-
 // Parse JSON to find the "text" key
 // Parse JSON to find the "text" key
 char *flip_library_parse_random_fact()
 char *flip_library_parse_random_fact()
 {
 {
@@ -274,6 +195,7 @@ static void view_draw_callback_random_facts(Canvas *canvas, void *model)
                 canvas_draw_str(canvas, 0, 22, "Processing...");
                 canvas_draw_str(canvas, 0, 22, "Processing...");
                 // success
                 // success
                 // check status
                 // check status
+                // unnecessary check
                 if (fhttp.state == ISSUE || fhttp.received_data == NULL)
                 if (fhttp.state == ISSUE || fhttp.received_data == NULL)
                 {
                 {
                     flip_library_request_error(canvas);
                     flip_library_request_error(canvas);

+ 0 - 4
flipper_http.h

@@ -248,10 +248,6 @@ bool flipper_http_init(FlipperHTTP_Callback callback, void *context)
     furi_thread_start(fhttp.rx_thread);
     furi_thread_start(fhttp.rx_thread);
     fhttp.rx_thread_id = furi_thread_get_id(fhttp.rx_thread);
     fhttp.rx_thread_id = furi_thread_get_id(fhttp.rx_thread);
 
 
-    // Initialize GPIO pins for UART
-    // furi_hal_gpio_init_simple(&test_pins[0], GpioModeInput);
-    // furi_hal_gpio_init_simple(&test_pins[1], GpioModeOutputPushPull);
-
     // handle when the UART control is busy to avoid furi_check failed
     // handle when the UART control is busy to avoid furi_check failed
     if (furi_hal_serial_control_is_busy(UART_CH))
     if (furi_hal_serial_control_is_busy(UART_CH))
     {
     {

+ 739 - 360
jsmn.h

@@ -27,7 +27,8 @@
 #include <stddef.h>
 #include <stddef.h>
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
-extern "C" {
+extern "C"
+{
 #endif
 #endif
 
 
 #ifdef JSMN_STATIC
 #ifdef JSMN_STATIC
@@ -36,431 +37,487 @@ extern "C" {
 #define JSMN_API extern
 #define JSMN_API extern
 #endif
 #endif
 
 
-/**
- * JSON type identifier. Basic types are:
- * 	o Object
- * 	o Array
- * 	o String
- * 	o Other primitive: number, boolean (true/false) or null
- */
-typedef enum {
-  JSMN_UNDEFINED = 0,
-  JSMN_OBJECT = 1 << 0,
-  JSMN_ARRAY = 1 << 1,
-  JSMN_STRING = 1 << 2,
-  JSMN_PRIMITIVE = 1 << 3
-} jsmntype_t;
-
-enum jsmnerr {
-  /* Not enough tokens were provided */
-  JSMN_ERROR_NOMEM = -1,
-  /* Invalid character inside JSON string */
-  JSMN_ERROR_INVAL = -2,
-  /* The string is not a full JSON packet, more bytes expected */
-  JSMN_ERROR_PART = -3
-};
-
-/**
- * JSON token description.
- * type		type (object, array, string etc.)
- * start	start position in JSON data string
- * end		end position in JSON data string
- */
-typedef struct jsmntok {
-  jsmntype_t type;
-  int start;
-  int end;
-  int size;
+  /**
+   * JSON type identifier. Basic types are:
+   * 	o Object
+   * 	o Array
+   * 	o String
+   * 	o Other primitive: number, boolean (true/false) or null
+   */
+  typedef enum
+  {
+    JSMN_UNDEFINED = 0,
+    JSMN_OBJECT = 1 << 0,
+    JSMN_ARRAY = 1 << 1,
+    JSMN_STRING = 1 << 2,
+    JSMN_PRIMITIVE = 1 << 3
+  } jsmntype_t;
+
+  enum jsmnerr
+  {
+    /* Not enough tokens were provided */
+    JSMN_ERROR_NOMEM = -1,
+    /* Invalid character inside JSON string */
+    JSMN_ERROR_INVAL = -2,
+    /* The string is not a full JSON packet, more bytes expected */
+    JSMN_ERROR_PART = -3
+  };
+
+  /**
+   * JSON token description.
+   * type		type (object, array, string etc.)
+   * start	start position in JSON data string
+   * end		end position in JSON data string
+   */
+  typedef struct jsmntok
+  {
+    jsmntype_t type;
+    int start;
+    int end;
+    int size;
 #ifdef JSMN_PARENT_LINKS
 #ifdef JSMN_PARENT_LINKS
-  int parent;
+    int parent;
 #endif
 #endif
-} jsmntok_t;
+  } jsmntok_t;
 
 
-/**
- * JSON parser. Contains an array of token blocks available. Also stores
- * the string being parsed now and current position in that string.
- */
-typedef struct jsmn_parser {
-  unsigned int pos;     /* offset in the JSON string */
-  unsigned int toknext; /* next token to allocate */
-  int toksuper;         /* superior token node, e.g. parent object or array */
-} jsmn_parser;
-
-/**
- * Create JSON parser over an array of tokens
- */
-JSMN_API void jsmn_init(jsmn_parser *parser);
+  /**
+   * JSON parser. Contains an array of token blocks available. Also stores
+   * the string being parsed now and current position in that string.
+   */
+  typedef struct jsmn_parser
+  {
+    unsigned int pos;     /* offset in the JSON string */
+    unsigned int toknext; /* next token to allocate */
+    int toksuper;         /* superior token node, e.g. parent object or array */
+  } jsmn_parser;
 
 
-/**
- * Run JSON parser. It parses a JSON data string into and array of tokens, each
- * describing
- * a single JSON object.
- */
-JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
-                        jsmntok_t *tokens, const unsigned int num_tokens);
+  /**
+   * Create JSON parser over an array of tokens
+   */
+  JSMN_API void jsmn_init(jsmn_parser *parser);
+
+  /**
+   * Run JSON parser. It parses a JSON data string into and array of tokens, each
+   * describing
+   * a single JSON object.
+   */
+  JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
+                          jsmntok_t *tokens, const unsigned int num_tokens);
 
 
 #ifndef JSMN_HEADER
 #ifndef JSMN_HEADER
-/**
- * Allocates a fresh unused token from the token pool.
- */
-static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens,
-                                   const size_t num_tokens) {
-  jsmntok_t *tok;
-  if (parser->toknext >= num_tokens) {
-    return NULL;
-  }
-  tok = &tokens[parser->toknext++];
-  tok->start = tok->end = -1;
-  tok->size = 0;
+  /**
+   * Allocates a fresh unused token from the token pool.
+   */
+  static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens,
+                                     const size_t num_tokens)
+  {
+    jsmntok_t *tok;
+    if (parser->toknext >= num_tokens)
+    {
+      return NULL;
+    }
+    tok = &tokens[parser->toknext++];
+    tok->start = tok->end = -1;
+    tok->size = 0;
 #ifdef JSMN_PARENT_LINKS
 #ifdef JSMN_PARENT_LINKS
-  tok->parent = -1;
+    tok->parent = -1;
 #endif
 #endif
-  return tok;
-}
+    return tok;
+  }
 
 
-/**
- * Fills token type and boundaries.
- */
-static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type,
-                            const int start, const int end) {
-  token->type = type;
-  token->start = start;
-  token->end = end;
-  token->size = 0;
-}
+  /**
+   * Fills token type and boundaries.
+   */
+  static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type,
+                              const int start, const int end)
+  {
+    token->type = type;
+    token->start = start;
+    token->end = end;
+    token->size = 0;
+  }
 
 
-/**
- * Fills next available token with JSON primitive.
- */
-static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
-                                const size_t len, jsmntok_t *tokens,
-                                const size_t num_tokens) {
-  jsmntok_t *token;
-  int start;
+  /**
+   * Fills next available token with JSON primitive.
+   */
+  static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
+                                  const size_t len, jsmntok_t *tokens,
+                                  const size_t num_tokens)
+  {
+    jsmntok_t *token;
+    int start;
 
 
-  start = parser->pos;
+    start = parser->pos;
 
 
-  for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
-    switch (js[parser->pos]) {
+    for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
+    {
+      switch (js[parser->pos])
+      {
 #ifndef JSMN_STRICT
 #ifndef JSMN_STRICT
-    /* In strict mode primitive must be followed by "," or "}" or "]" */
-    case ':':
+      /* In strict mode primitive must be followed by "," or "}" or "]" */
+      case ':':
 #endif
 #endif
-    case '\t':
-    case '\r':
-    case '\n':
-    case ' ':
-    case ',':
-    case ']':
-    case '}':
-      goto found;
-    default:
-                   /* to quiet a warning from gcc*/
-      break;
-    }
-    if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
-      parser->pos = start;
-      return JSMN_ERROR_INVAL;
+      case '\t':
+      case '\r':
+      case '\n':
+      case ' ':
+      case ',':
+      case ']':
+      case '}':
+        goto found;
+      default:
+        /* to quiet a warning from gcc*/
+        break;
+      }
+      if (js[parser->pos] < 32 || js[parser->pos] >= 127)
+      {
+        parser->pos = start;
+        return JSMN_ERROR_INVAL;
+      }
     }
     }
-  }
 #ifdef JSMN_STRICT
 #ifdef JSMN_STRICT
-  /* In strict mode primitive must be followed by a comma/object/array */
-  parser->pos = start;
-  return JSMN_ERROR_PART;
+    /* In strict mode primitive must be followed by a comma/object/array */
+    parser->pos = start;
+    return JSMN_ERROR_PART;
 #endif
 #endif
 
 
-found:
-  if (tokens == NULL) {
+  found:
+    if (tokens == NULL)
+    {
+      parser->pos--;
+      return 0;
+    }
+    token = jsmn_alloc_token(parser, tokens, num_tokens);
+    if (token == NULL)
+    {
+      parser->pos = start;
+      return JSMN_ERROR_NOMEM;
+    }
+    jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+    token->parent = parser->toksuper;
+#endif
     parser->pos--;
     parser->pos--;
     return 0;
     return 0;
   }
   }
-  token = jsmn_alloc_token(parser, tokens, num_tokens);
-  if (token == NULL) {
-    parser->pos = start;
-    return JSMN_ERROR_NOMEM;
-  }
-  jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
+
+  /**
+   * Fills next token with JSON string.
+   */
+  static int jsmn_parse_string(jsmn_parser *parser, const char *js,
+                               const size_t len, jsmntok_t *tokens,
+                               const size_t num_tokens)
+  {
+    jsmntok_t *token;
+
+    int start = parser->pos;
+
+    /* Skip starting quote */
+    parser->pos++;
+
+    for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
+    {
+      char c = js[parser->pos];
+
+      /* Quote: end of string */
+      if (c == '\"')
+      {
+        if (tokens == NULL)
+        {
+          return 0;
+        }
+        token = jsmn_alloc_token(parser, tokens, num_tokens);
+        if (token == NULL)
+        {
+          parser->pos = start;
+          return JSMN_ERROR_NOMEM;
+        }
+        jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);
 #ifdef JSMN_PARENT_LINKS
 #ifdef JSMN_PARENT_LINKS
-  token->parent = parser->toksuper;
+        token->parent = parser->toksuper;
 #endif
 #endif
-  parser->pos--;
-  return 0;
-}
-
-/**
- * Fills next token with JSON string.
- */
-static int jsmn_parse_string(jsmn_parser *parser, const char *js,
-                             const size_t len, jsmntok_t *tokens,
-                             const size_t num_tokens) {
-  jsmntok_t *token;
-
-  int start = parser->pos;
-  
-  /* Skip starting quote */
-  parser->pos++;
-  
-  for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
-    char c = js[parser->pos];
-
-    /* Quote: end of string */
-    if (c == '\"') {
-      if (tokens == NULL) {
         return 0;
         return 0;
       }
       }
-      token = jsmn_alloc_token(parser, tokens, num_tokens);
-      if (token == NULL) {
-        parser->pos = start;
-        return JSMN_ERROR_NOMEM;
-      }
-      jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);
-#ifdef JSMN_PARENT_LINKS
-      token->parent = parser->toksuper;
-#endif
-      return 0;
-    }
 
 
-    /* Backslash: Quoted symbol expected */
-    if (c == '\\' && parser->pos + 1 < len) {
-      int i;
-      parser->pos++;
-      switch (js[parser->pos]) {
-      /* Allowed escaped symbols */
-      case '\"':
-      case '/':
-      case '\\':
-      case 'b':
-      case 'f':
-      case 'r':
-      case 'n':
-      case 't':
-        break;
-      /* Allows escaped symbol \uXXXX */
-      case 'u':
+      /* Backslash: Quoted symbol expected */
+      if (c == '\\' && parser->pos + 1 < len)
+      {
+        int i;
         parser->pos++;
         parser->pos++;
-        for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0';
-             i++) {
-          /* If it isn't a hex character we have an error */
-          if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) ||   /* 0-9 */
-                (js[parser->pos] >= 65 && js[parser->pos] <= 70) ||   /* A-F */
-                (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
-            parser->pos = start;
-            return JSMN_ERROR_INVAL;
-          }
+        switch (js[parser->pos])
+        {
+        /* Allowed escaped symbols */
+        case '\"':
+        case '/':
+        case '\\':
+        case 'b':
+        case 'f':
+        case 'r':
+        case 'n':
+        case 't':
+          break;
+        /* Allows escaped symbol \uXXXX */
+        case 'u':
           parser->pos++;
           parser->pos++;
+          for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0';
+               i++)
+          {
+            /* If it isn't a hex character we have an error */
+            if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
+                  (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
+                  (js[parser->pos] >= 97 && js[parser->pos] <= 102)))
+            { /* a-f */
+              parser->pos = start;
+              return JSMN_ERROR_INVAL;
+            }
+            parser->pos++;
+          }
+          parser->pos--;
+          break;
+        /* Unexpected symbol */
+        default:
+          parser->pos = start;
+          return JSMN_ERROR_INVAL;
         }
         }
-        parser->pos--;
-        break;
-      /* Unexpected symbol */
-      default:
-        parser->pos = start;
-        return JSMN_ERROR_INVAL;
       }
       }
     }
     }
+    parser->pos = start;
+    return JSMN_ERROR_PART;
   }
   }
-  parser->pos = start;
-  return JSMN_ERROR_PART;
-}
 
 
-/**
- * Parse JSON string and fill tokens.
- */
-JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
-                        jsmntok_t *tokens, const unsigned int num_tokens) {
-  int r;
-  int i;
-  jsmntok_t *token;
-  int count = parser->toknext;
-
-  for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
-    char c;
-    jsmntype_t type;
+  /**
+   * Parse JSON string and fill tokens.
+   */
+  JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
+                          jsmntok_t *tokens, const unsigned int num_tokens)
+  {
+    int r;
+    int i;
+    jsmntok_t *token;
+    int count = parser->toknext;
 
 
-    c = js[parser->pos];
-    switch (c) {
-    case '{':
-    case '[':
-      count++;
-      if (tokens == NULL) {
-        break;
-      }
-      token = jsmn_alloc_token(parser, tokens, num_tokens);
-      if (token == NULL) {
-        return JSMN_ERROR_NOMEM;
-      }
-      if (parser->toksuper != -1) {
-        jsmntok_t *t = &tokens[parser->toksuper];
-#ifdef JSMN_STRICT
-        /* In strict mode an object or array can't become a key */
-        if (t->type == JSMN_OBJECT) {
-          return JSMN_ERROR_INVAL;
+    for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
+    {
+      char c;
+      jsmntype_t type;
+
+      c = js[parser->pos];
+      switch (c)
+      {
+      case '{':
+      case '[':
+        count++;
+        if (tokens == NULL)
+        {
+          break;
+        }
+        token = jsmn_alloc_token(parser, tokens, num_tokens);
+        if (token == NULL)
+        {
+          return JSMN_ERROR_NOMEM;
         }
         }
+        if (parser->toksuper != -1)
+        {
+          jsmntok_t *t = &tokens[parser->toksuper];
+#ifdef JSMN_STRICT
+          /* In strict mode an object or array can't become a key */
+          if (t->type == JSMN_OBJECT)
+          {
+            return JSMN_ERROR_INVAL;
+          }
 #endif
 #endif
-        t->size++;
+          t->size++;
 #ifdef JSMN_PARENT_LINKS
 #ifdef JSMN_PARENT_LINKS
-        token->parent = parser->toksuper;
+          token->parent = parser->toksuper;
 #endif
 #endif
-      }
-      token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
-      token->start = parser->pos;
-      parser->toksuper = parser->toknext - 1;
-      break;
-    case '}':
-    case ']':
-      if (tokens == NULL) {
+        }
+        token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
+        token->start = parser->pos;
+        parser->toksuper = parser->toknext - 1;
         break;
         break;
-      }
-      type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
-#ifdef JSMN_PARENT_LINKS
-      if (parser->toknext < 1) {
-        return JSMN_ERROR_INVAL;
-      }
-      token = &tokens[parser->toknext - 1];
-      for (;;) {
-        if (token->start != -1 && token->end == -1) {
-          if (token->type != type) {
-            return JSMN_ERROR_INVAL;
-          }
-          token->end = parser->pos + 1;
-          parser->toksuper = token->parent;
+      case '}':
+      case ']':
+        if (tokens == NULL)
+        {
           break;
           break;
         }
         }
-        if (token->parent == -1) {
-          if (token->type != type || parser->toksuper == -1) {
-            return JSMN_ERROR_INVAL;
+        type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
+#ifdef JSMN_PARENT_LINKS
+        if (parser->toknext < 1)
+        {
+          return JSMN_ERROR_INVAL;
+        }
+        token = &tokens[parser->toknext - 1];
+        for (;;)
+        {
+          if (token->start != -1 && token->end == -1)
+          {
+            if (token->type != type)
+            {
+              return JSMN_ERROR_INVAL;
+            }
+            token->end = parser->pos + 1;
+            parser->toksuper = token->parent;
+            break;
           }
           }
-          break;
+          if (token->parent == -1)
+          {
+            if (token->type != type || parser->toksuper == -1)
+            {
+              return JSMN_ERROR_INVAL;
+            }
+            break;
+          }
+          token = &tokens[token->parent];
         }
         }
-        token = &tokens[token->parent];
-      }
 #else
 #else
-      for (i = parser->toknext - 1; i >= 0; i--) {
-        token = &tokens[i];
-        if (token->start != -1 && token->end == -1) {
-          if (token->type != type) {
-            return JSMN_ERROR_INVAL;
+        for (i = parser->toknext - 1; i >= 0; i--)
+        {
+          token = &tokens[i];
+          if (token->start != -1 && token->end == -1)
+          {
+            if (token->type != type)
+            {
+              return JSMN_ERROR_INVAL;
+            }
+            parser->toksuper = -1;
+            token->end = parser->pos + 1;
+            break;
           }
           }
-          parser->toksuper = -1;
-          token->end = parser->pos + 1;
-          break;
         }
         }
-      }
-      /* Error if unmatched closing bracket */
-      if (i == -1) {
-        return JSMN_ERROR_INVAL;
-      }
-      for (; i >= 0; i--) {
-        token = &tokens[i];
-        if (token->start != -1 && token->end == -1) {
-          parser->toksuper = i;
-          break;
+        /* Error if unmatched closing bracket */
+        if (i == -1)
+        {
+          return JSMN_ERROR_INVAL;
+        }
+        for (; i >= 0; i--)
+        {
+          token = &tokens[i];
+          if (token->start != -1 && token->end == -1)
+          {
+            parser->toksuper = i;
+            break;
+          }
         }
         }
-      }
 #endif
 #endif
-      break;
-    case '\"':
-      r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
-      if (r < 0) {
-        return r;
-      }
-      count++;
-      if (parser->toksuper != -1 && tokens != NULL) {
-        tokens[parser->toksuper].size++;
-      }
-      break;
-    case '\t':
-    case '\r':
-    case '\n':
-    case ' ':
-      break;
-    case ':':
-      parser->toksuper = parser->toknext - 1;
-      break;
-    case ',':
-      if (tokens != NULL && parser->toksuper != -1 &&
-          tokens[parser->toksuper].type != JSMN_ARRAY &&
-          tokens[parser->toksuper].type != JSMN_OBJECT) {
+        break;
+      case '\"':
+        r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
+        if (r < 0)
+        {
+          return r;
+        }
+        count++;
+        if (parser->toksuper != -1 && tokens != NULL)
+        {
+          tokens[parser->toksuper].size++;
+        }
+        break;
+      case '\t':
+      case '\r':
+      case '\n':
+      case ' ':
+        break;
+      case ':':
+        parser->toksuper = parser->toknext - 1;
+        break;
+      case ',':
+        if (tokens != NULL && parser->toksuper != -1 &&
+            tokens[parser->toksuper].type != JSMN_ARRAY &&
+            tokens[parser->toksuper].type != JSMN_OBJECT)
+        {
 #ifdef JSMN_PARENT_LINKS
 #ifdef JSMN_PARENT_LINKS
-        parser->toksuper = tokens[parser->toksuper].parent;
+          parser->toksuper = tokens[parser->toksuper].parent;
 #else
 #else
-        for (i = parser->toknext - 1; i >= 0; i--) {
-          if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
-            if (tokens[i].start != -1 && tokens[i].end == -1) {
-              parser->toksuper = i;
-              break;
+          for (i = parser->toknext - 1; i >= 0; i--)
+          {
+            if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT)
+            {
+              if (tokens[i].start != -1 && tokens[i].end == -1)
+              {
+                parser->toksuper = i;
+                break;
+              }
             }
             }
           }
           }
-        }
 #endif
 #endif
-      }
-      break;
+        }
+        break;
 #ifdef JSMN_STRICT
 #ifdef JSMN_STRICT
-    /* In strict mode primitives are: numbers and booleans */
-    case '-':
-    case '0':
-    case '1':
-    case '2':
-    case '3':
-    case '4':
-    case '5':
-    case '6':
-    case '7':
-    case '8':
-    case '9':
-    case 't':
-    case 'f':
-    case 'n':
-      /* And they must not be keys of the object */
-      if (tokens != NULL && parser->toksuper != -1) {
-        const jsmntok_t *t = &tokens[parser->toksuper];
-        if (t->type == JSMN_OBJECT ||
-            (t->type == JSMN_STRING && t->size != 0)) {
-          return JSMN_ERROR_INVAL;
+      /* In strict mode primitives are: numbers and booleans */
+      case '-':
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+      case 't':
+      case 'f':
+      case 'n':
+        /* And they must not be keys of the object */
+        if (tokens != NULL && parser->toksuper != -1)
+        {
+          const jsmntok_t *t = &tokens[parser->toksuper];
+          if (t->type == JSMN_OBJECT ||
+              (t->type == JSMN_STRING && t->size != 0))
+          {
+            return JSMN_ERROR_INVAL;
+          }
         }
         }
-      }
 #else
 #else
-    /* In non-strict mode every unquoted value is a primitive */
-    default:
+      /* In non-strict mode every unquoted value is a primitive */
+      default:
 #endif
 #endif
-      r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
-      if (r < 0) {
-        return r;
-      }
-      count++;
-      if (parser->toksuper != -1 && tokens != NULL) {
-        tokens[parser->toksuper].size++;
-      }
-      break;
+        r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
+        if (r < 0)
+        {
+          return r;
+        }
+        count++;
+        if (parser->toksuper != -1 && tokens != NULL)
+        {
+          tokens[parser->toksuper].size++;
+        }
+        break;
 
 
 #ifdef JSMN_STRICT
 #ifdef JSMN_STRICT
-    /* Unexpected char in strict mode */
-    default:
-      return JSMN_ERROR_INVAL;
+      /* Unexpected char in strict mode */
+      default:
+        return JSMN_ERROR_INVAL;
 #endif
 #endif
+      }
     }
     }
-  }
 
 
-  if (tokens != NULL) {
-    for (i = parser->toknext - 1; i >= 0; i--) {
-      /* Unmatched opened object or array */
-      if (tokens[i].start != -1 && tokens[i].end == -1) {
-        return JSMN_ERROR_PART;
+    if (tokens != NULL)
+    {
+      for (i = parser->toknext - 1; i >= 0; i--)
+      {
+        /* Unmatched opened object or array */
+        if (tokens[i].start != -1 && tokens[i].end == -1)
+        {
+          return JSMN_ERROR_PART;
+        }
       }
       }
     }
     }
-  }
 
 
-  return count;
-}
+    return count;
+  }
 
 
-/**
- * Creates a new parser based over a given buffer with an array of tokens
- * available.
- */
-JSMN_API void jsmn_init(jsmn_parser *parser) {
-  parser->pos = 0;
-  parser->toknext = 0;
-  parser->toksuper = -1;
-}
+  /**
+   * Creates a new parser based over a given buffer with an array of tokens
+   * available.
+   */
+  JSMN_API void jsmn_init(jsmn_parser *parser)
+  {
+    parser->pos = 0;
+    parser->toknext = 0;
+    parser->toksuper = -1;
+  }
 
 
 #endif /* JSMN_HEADER */
 #endif /* JSMN_HEADER */
 
 
@@ -469,3 +526,325 @@ JSMN_API void jsmn_init(jsmn_parser *parser) {
 #endif
 #endif
 
 
 #endif /* JSMN_H */
 #endif /* JSMN_H */
+
+#ifndef JB_JSMN_EDIT
+#define JB_JSMN_EDIT
+/* Added in by JBlanked on 2024-10-16 for use in Flipper Zero SDK*/
+
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <furi.h>
+
+// Helper function to compare JSON keys
+int jsoneq(const char *json, jsmntok_t *tok, const char *s)
+{
+  if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start &&
+      strncmp(json + tok->start, s, tok->end - tok->start) == 0)
+  {
+    return 0;
+  }
+  return -1;
+}
+
+// return the value of the key in the JSON data
+char *get_json_value(char *key, char *json_data, uint32_t max_tokens)
+{
+  // Parse the JSON feed
+  if (json_data != NULL)
+  {
+    jsmn_parser parser;
+    jsmn_init(&parser);
+
+    // Allocate tokens array on the heap
+    jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * max_tokens);
+    if (tokens == NULL)
+    {
+      FURI_LOG_E("JSMM.H", "Failed to allocate memory for JSON tokens.");
+      return NULL;
+    }
+
+    int ret = jsmn_parse(&parser, json_data, strlen(json_data), tokens, max_tokens);
+    if (ret < 0)
+    {
+      // Handle parsing errors
+      FURI_LOG_E("JSMM.H", "Failed to parse JSON: %d", ret);
+      free(tokens);
+      return NULL;
+    }
+
+    // Ensure that the root element is an object
+    if (ret < 1 || tokens[0].type != JSMN_OBJECT)
+    {
+      FURI_LOG_E("JSMM.H", "Root element is not an object.");
+      free(tokens);
+      return NULL;
+    }
+
+    // Loop through the tokens to find the key
+    for (int i = 1; i < ret; i++)
+    {
+      if (jsoneq(json_data, &tokens[i], key) == 0)
+      {
+        // We found the key. Now, return the associated value.
+        int length = tokens[i + 1].end - tokens[i + 1].start;
+        char *value = malloc(length + 1);
+        if (value == NULL)
+        {
+          FURI_LOG_E("JSMM.H", "Failed to allocate memory for value.");
+          free(tokens);
+          return NULL;
+        }
+        strncpy(value, json_data + tokens[i + 1].start, length);
+        value[length] = '\0'; // Null-terminate the string
+
+        free(tokens); // Free the token array
+        return value; // Return the extracted value
+      }
+    }
+
+    // Free the token array if key was not found
+    free(tokens);
+  }
+  else
+  {
+    FURI_LOG_E("JSMM.H", "JSON data is NULL");
+  }
+  FURI_LOG_E("JSMM.H", "Failed to find the key in the JSON.");
+  return NULL; // Return NULL if something goes wrong
+}
+
+// Revised get_json_array_value function
+char *get_json_array_value(char *key, uint32_t index, char *json_data, uint32_t max_tokens)
+{
+  // Retrieve the array string for the given key
+  char *array_str = get_json_value(key, json_data, max_tokens);
+  if (array_str == NULL)
+  {
+    FURI_LOG_E("JSMM.H", "Failed to get array for key: %s", key);
+    return NULL;
+  }
+
+  // Initialize the JSON parser
+  jsmn_parser parser;
+  jsmn_init(&parser);
+
+  // Allocate memory for JSON tokens
+  jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * max_tokens);
+  if (tokens == NULL)
+  {
+    FURI_LOG_E("JSMM.H", "Failed to allocate memory for JSON tokens.");
+    free(array_str);
+    return NULL;
+  }
+
+  // Parse the JSON array
+  int ret = jsmn_parse(&parser, array_str, strlen(array_str), tokens, max_tokens);
+  if (ret < 0)
+  {
+    FURI_LOG_E("JSMM.H", "Failed to parse JSON array: %d", ret);
+    free(tokens);
+    free(array_str);
+    return NULL;
+  }
+
+  // Ensure the root element is an array
+  if (ret < 1 || tokens[0].type != JSMN_ARRAY)
+  {
+    FURI_LOG_E("JSMM.H", "Value for key '%s' is not an array.", key);
+    free(tokens);
+    free(array_str);
+    return NULL;
+  }
+
+  // Check if the index is within bounds
+  if (index >= (uint32_t)tokens[0].size)
+  {
+    FURI_LOG_E("JSMM.H", "Index %lu out of bounds for array with size %d.", (unsigned long)index, tokens[0].size);
+    free(tokens);
+    free(array_str);
+    return NULL;
+  }
+
+  // Locate the token corresponding to the desired array element
+  int current_token = 1; // Start after the array token
+  for (uint32_t i = 0; i < index; i++)
+  {
+    if (tokens[current_token].type == JSMN_OBJECT)
+    {
+      // For objects, skip all key-value pairs
+      current_token += 1 + 2 * tokens[current_token].size;
+    }
+    else if (tokens[current_token].type == JSMN_ARRAY)
+    {
+      // For nested arrays, skip all elements
+      current_token += 1 + tokens[current_token].size;
+    }
+    else
+    {
+      // For primitive types, simply move to the next token
+      current_token += 1;
+    }
+
+    // Safety check to prevent out-of-bounds
+    if (current_token >= ret)
+    {
+      FURI_LOG_E("JSMM.H", "Unexpected end of tokens while traversing array.");
+      free(tokens);
+      free(array_str);
+      return NULL;
+    }
+  }
+
+  // Extract the array element
+  jsmntok_t element = tokens[current_token];
+  int length = element.end - element.start;
+  char *value = malloc(length + 1);
+  if (value == NULL)
+  {
+    FURI_LOG_E("JSMM.H", "Failed to allocate memory for array element.");
+    free(tokens);
+    free(array_str);
+    return NULL;
+  }
+
+  // Copy the element value to a new string
+  strncpy(value, array_str + element.start, length);
+  value[length] = '\0'; // Null-terminate the string
+
+  // Clean up
+  free(tokens);
+  free(array_str);
+
+  return value;
+}
+
+// Revised get_json_array_values function with correct token skipping
+char **get_json_array_values(char *key, char *json_data, uint32_t max_tokens, int *num_values)
+{
+  // Retrieve the array string for the given key
+  char *array_str = get_json_value(key, json_data, max_tokens);
+  if (array_str == NULL)
+  {
+    FURI_LOG_E("JSMM.H", "Failed to get array for key: %s", key);
+    return NULL;
+  }
+
+  // Initialize the JSON parser
+  jsmn_parser parser;
+  jsmn_init(&parser);
+
+  // Allocate memory for JSON tokens
+  jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * max_tokens); // Allocate on the heap
+  if (tokens == NULL)
+  {
+    FURI_LOG_E("JSMM.H", "Failed to allocate memory for JSON tokens.");
+    free(array_str);
+    return NULL;
+  }
+
+  // Parse the JSON array
+  int ret = jsmn_parse(&parser, array_str, strlen(array_str), tokens, max_tokens);
+  if (ret < 0)
+  {
+    FURI_LOG_E("JSMM.H", "Failed to parse JSON array: %d", ret);
+    free(tokens);
+    free(array_str);
+    return NULL;
+  }
+
+  // Ensure the root element is an array
+  if (tokens[0].type != JSMN_ARRAY)
+  {
+    FURI_LOG_E("JSMM.H", "Value for key '%s' is not an array.", key);
+    free(tokens);
+    free(array_str);
+    return NULL;
+  }
+
+  // Allocate memory for the array of values (maximum possible)
+  int array_size = tokens[0].size;
+  char **values = malloc(array_size * sizeof(char *));
+  if (values == NULL)
+  {
+    FURI_LOG_E("JSMM.H", "Failed to allocate memory for array of values.");
+    free(tokens);
+    free(array_str);
+    return NULL;
+  }
+
+  int actual_num_values = 0;
+
+  // Traverse the array and extract all object values
+  int current_token = 1; // Start after the array token
+  for (int i = 0; i < array_size; i++)
+  {
+    if (current_token >= ret)
+    {
+      FURI_LOG_E("JSMM.H", "Unexpected end of tokens while traversing array.");
+      break;
+    }
+
+    jsmntok_t element = tokens[current_token];
+
+    if (element.type != JSMN_OBJECT)
+    {
+      FURI_LOG_E("JSMM.H", "Array element %d is not an object, skipping.", i);
+      // Skip this element
+      current_token += 1;
+      continue;
+    }
+
+    int length = element.end - element.start;
+
+    // Allocate a new string for the value and copy the data
+    char *value = malloc(length + 1);
+    if (value == NULL)
+    {
+      FURI_LOG_E("JSMM.H", "Failed to allocate memory for array element.");
+      for (int j = 0; j < actual_num_values; j++)
+      {
+        free(values[j]);
+      }
+      free(values);
+      free(tokens);
+      free(array_str);
+      return NULL;
+    }
+
+    strncpy(value, array_str + element.start, length);
+    value[length] = '\0'; // Null-terminate the string
+
+    values[actual_num_values] = value;
+    actual_num_values++;
+
+    // Skip all tokens related to this object to avoid misparsing
+    current_token += 1 + (2 * element.size); // Each key-value pair consumes two tokens
+  }
+
+  *num_values = actual_num_values;
+
+  // Reallocate the values array to actual_num_values if necessary
+  if (actual_num_values < array_size)
+  {
+    char **reduced_values = realloc(values, actual_num_values * sizeof(char *));
+    if (reduced_values != NULL)
+    {
+      values = reduced_values;
+    }
+
+    // Free the remaining values
+    for (int i = actual_num_values; i < array_size; i++)
+    {
+      free(values[i]);
+    }
+  }
+
+  // Clean up
+  free(tokens);
+  free(array_str);
+  return values;
+}
+
+#endif /* JB_JSMN_EDIT */