1+ #include "cJSON.h"
2+ #include "class/hid/hid_device.h"
3+ #include "esp_log.h"
4+ #include "esp_spiffs.h"
5+ #include "freertos/FreeRTOS.h"
6+ #include "freertos/queue.h"
7+ #include "freertos/task.h"
8+ #include "macrolev.h"
9+ #include "sdkconfig.h"
10+ #include "tinyusb.h"
11+ #include "tusb_cdc_acm.h"
12+ #include <stdio.h>
13+ #include <string.h>
14+
15+ static const char * TAG = "MACROLEV" ;
16+
17+ #define BOOT_MODE_PIN GPIO_NUM_0
18+ #define STORAGE_NAMESPACE "storage"
19+ #define JSON_FILENAME "config.json"
20+ #define CDC_ACCUM_BUF_SIZE (1024 * 1024) // 1MB buffer for large JSON payloads
21+
22+ #define MARKER "[EOF]"
23+ #define MARKER_LEN (sizeof(MARKER) - 1)
24+
25+ static char cdc_accum_buf [CDC_ACCUM_BUF_SIZE ];
26+ static size_t cdc_accum_len = 0 ;
27+
28+ static uint8_t rx_buffer [CONFIG_TINYUSB_CDC_RX_BUFSIZE + 1 ];
29+
30+ static QueueHandle_t usb_cdc_rx_queue ;
31+
32+ typedef struct usb_message {
33+ uint8_t buf [CONFIG_TINYUSB_CDC_RX_BUFSIZE + 1 ];
34+ size_t buf_len ;
35+ } usb_message_t ;
36+
37+ static void usb_cdc_rx_queue_handler_task (void * pvParameters ) {
38+ usb_message_t msg ;
39+
40+ while (1 ) {
41+ if (xQueueReceive (usb_cdc_rx_queue , & msg , portMAX_DELAY ) == pdTRUE ) {
42+ ESP_LOGI (TAG , "Received %d bytes from USB" , msg .buf_len );
43+
44+ // Check for buffer overflow
45+ if (cdc_accum_len + msg .buf_len < CDC_ACCUM_BUF_SIZE ) {
46+ memcpy (& cdc_accum_buf [cdc_accum_len ], msg .buf , msg .buf_len );
47+ cdc_accum_len += msg .buf_len ;
48+
49+ // Search for marker
50+ if (cdc_accum_len >= MARKER_LEN ) {
51+ for (size_t i = 0 ; i <= cdc_accum_len - MARKER_LEN ; ++ i ) {
52+ if (memcmp (& cdc_accum_buf [i ], MARKER , MARKER_LEN ) == 0 ) {
53+ ESP_LOGI (TAG , "Marker detected ([EOF]) at position %d. Attempting to parse JSON." , (int )i );
54+ cdc_accum_buf [i ] = '\0' ; // Null-terminate before marker
55+
56+ // Try to parse as JSON
57+ cJSON * json = cJSON_Parse (cdc_accum_buf );
58+ if (json != NULL ) {
59+ ESP_LOGI (TAG , "Valid JSON received, saving to config.json" );
60+ save_json_to_file (JSON_FILENAME , json );
61+ cJSON_Delete (json );
62+ } else {
63+ ESP_LOGE (TAG , "Invalid JSON received. Parse failed." );
64+ }
65+
66+ // Move any data after the marker to the start of the buffer
67+ size_t remaining = cdc_accum_len - (i + MARKER_LEN );
68+ if (remaining > 0 ) {
69+ memmove (cdc_accum_buf , & cdc_accum_buf [i + MARKER_LEN ], remaining );
70+ }
71+ cdc_accum_len = remaining ;
72+ break ;
73+ }
74+ }
75+ }
76+ } else {
77+ ESP_LOGE (TAG , "CDC accumulation buffer overflow. Resetting buffer." );
78+ cdc_accum_len = 0 ;
79+ }
80+ }
81+ }
82+ }
83+
84+ // Initialize SPIFFS
85+ static esp_err_t init_spiffs (void ) {
86+ ESP_LOGI (TAG , "Initializing SPIFFS" );
87+
88+ esp_vfs_spiffs_conf_t conf = {
89+ .base_path = "/" ,
90+ .partition_label = NULL ,
91+ .max_files = 1 ,
92+ .format_if_mount_failed = true
93+ };
94+
95+ esp_err_t ret = esp_vfs_spiffs_register (& conf );
96+ if (ret != ESP_OK ) {
97+ ESP_LOGE (TAG , "Failed to initialize SPIFFS (%s)" , esp_err_to_name (ret ));
98+ return ret ;
99+ }
100+
101+ size_t total = 0 , used = 0 ;
102+ ret = esp_spiffs_info (NULL , & total , & used );
103+ if (ret != ESP_OK ) {
104+ ESP_LOGE (TAG , "Failed to get SPIFFS partition information (%s)" , esp_err_to_name (ret ));
105+ return ret ;
106+ }
107+
108+ ESP_LOGI (TAG , "Partition size: total: %d, used: %d" , total , used );
109+ return ESP_OK ;
110+ }
111+
112+ // Save JSON to file
113+ esp_err_t save_json_to_file (const char * filename , cJSON * json ) {
114+ char * json_string = cJSON_PrintUnformatted (json );
115+ if (json_string == NULL ) {
116+ ESP_LOGE (TAG , "Failed to print json" );
117+ return ESP_FAIL ;
118+ }
119+
120+ char filepath [64 ];
121+ // snprintf(filepath, sizeof(filepath), "/%s", filename);
122+ snprintf (filepath , sizeof (filepath ), filename );
123+
124+ FILE * f = fopen (filepath , "w" );
125+ if (f == NULL ) {
126+ ESP_LOGE (TAG , "Failed to open file for writing" );
127+ free (json_string );
128+ return ESP_FAIL ;
129+ }
130+
131+ fprintf (f , "%s" , json_string );
132+ fclose (f );
133+ free (json_string );
134+
135+ ESP_LOGI (TAG , "JSON saved to file: %s" , filepath );
136+ ESP_LOGI (TAG , "JSON: %s" , cJSON_Print (json ));
137+ return ESP_OK ;
138+ }
139+
140+ // Load JSON from file
141+ cJSON * load_json_from_file (const char * filename ) {
142+ char filepath [64 ];
143+ // snprintf(filepath, sizeof(filepath), "/%s", filename);
144+ snprintf (filepath , sizeof (filepath ), filename );
145+
146+ FILE * f = fopen (filepath , "r" );
147+ if (f == NULL ) {
148+ ESP_LOGE (TAG , "Failed to open file for reading" );
149+ return NULL ;
150+ }
151+
152+ // Get file size
153+ fseek (f , 0 , SEEK_END );
154+ long fsize = ftell (f );
155+ fseek (f , 0 , SEEK_SET );
156+
157+ // Read file content
158+ char * content = malloc (fsize + 1 );
159+ if (content == NULL ) {
160+ ESP_LOGE (TAG , "Failed to allocate memory" );
161+ fclose (f );
162+ return NULL ;
163+ }
164+
165+ size_t read_size = fread (content , 1 , fsize , f );
166+ content [read_size ] = '\0' ;
167+ fclose (f );
168+
169+ // Parse JSON
170+ cJSON * json = cJSON_Parse (content );
171+ free (content );
172+
173+ if (json == NULL ) {
174+ const char * error_ptr = cJSON_GetErrorPtr ();
175+ if (error_ptr != NULL ) {
176+ ESP_LOGE (TAG , "Error parsing JSON before: %s" , error_ptr );
177+ }
178+ return NULL ;
179+ }
180+
181+ ESP_LOGI (TAG , "JSON loaded from file: %s" , filepath );
182+ return json ;
183+ }
184+
185+ void tinyusb_cdc_rx_callback (int itf , cdcacm_event_t * event ) {
186+ usb_message_t msg = { 0 };
187+ msg .buf_len = 0 ;
188+
189+ // Read data from CDC
190+ esp_err_t ret = tinyusb_cdcacm_read (itf , msg .buf , CONFIG_TINYUSB_CDC_RX_BUFSIZE , & msg .buf_len );
191+ if (ret == ESP_OK && msg .buf_len > 0 ) {
192+ // Send message to queue
193+ if (xQueueSend (usb_cdc_rx_queue , & msg , portMAX_DELAY ) != pdTRUE ) {
194+ ESP_LOGE (TAG , "Failed to send message to queue" );
195+ }
196+ }
197+ }
198+
199+ void config_storage_init (void ) {
200+ // Initialize SPIFFS
201+ ESP_ERROR_CHECK (init_spiffs ());
202+
203+ // Create the CDC RX queue
204+ usb_cdc_rx_queue = xQueueCreate (5 , sizeof (usb_message_t ));
205+ assert (usb_cdc_rx_queue );
206+
207+ // Create the CDC RX queue handler task
208+ xTaskCreate (usb_cdc_rx_queue_handler_task , "usb_cdc_rx_queue_handler" , 4096 , NULL , 5 , NULL );
209+
210+ // Initialize CDC
211+ tinyusb_config_cdcacm_t acm_cfg = {
212+ .usb_dev = TINYUSB_USBDEV_0 ,
213+ .cdc_port = TINYUSB_CDC_ACM_0 ,
214+ .callback_rx = & tinyusb_cdc_rx_callback ,
215+ .callback_rx_wanted_char = NULL ,
216+ .callback_line_state_changed = NULL ,
217+ .callback_line_coding_changed = NULL ,
218+ .rx_unread_buf_sz = CONFIG_TINYUSB_CDC_RX_BUFSIZE
219+ };
220+ ESP_ERROR_CHECK (tusb_cdc_acm_init (& acm_cfg ));
221+
222+ ESP_LOGI (TAG , "USB initialization DONE" );
223+ }
0 commit comments