Sub Process_Globals
'These global variables will be declared once when the application starts.
'Public variables can be accessed from all modules.
Dim result() As Byte 'ignore
Dim psram_json_size As Int ' full generated JSON size, bytes
Dim psramChunk(512) As Byte ' SRAM buffer for single chunk (check with HttpJob.chunkLength)
Dim psramChunkSize As Int ' how many copied
Dim psram_read_start As Int ' start index
Dim psram_read_len As Int 'length to be copied
End sub
'Reading JSON chunk from PSRAM to psramChunk
Public Sub ReadFromPSRAM(startIndex As Int, length As Int) As Int
psram_read_start = startIndex
psram_read_len = length
Return RunNative("read_from_psram", Null)
End Sub
Sub PrepareJSONinPSRAM
' ==== Generating JSON inside PSRAM ====
RunNative("prepare_json_psram", Null)
End Sub
#IF C
#ifdef ESP32
#include <Arduino.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
#endif
static char* json_psram = nullptr;
uint32_t psram_json_size = 0;
void prepare_json_psram(B4R::Object* o) {
if (json_psram) {
free(json_psram);
json_psram = nullptr;
}
size_t buf_size = 16384;
json_psram = (char*)ps_malloc(buf_size);
if (!json_psram) {
Serial.println("PSRAM alloc failed for JSON");
if (b4r_esp_vibro_fft::_result) {
b4r_esp_vibro_fft::_result->length = 0;
b4r_esp_vibro_fft::_result->data = nullptr;
}
return;
}
size_t len = 0;
auto append_raw = [&](const char* s) {
if (!s) return;
size_t sl = strlen(s);
if (len + sl + 1 >= buf_size) return;
memcpy(json_psram + len, s, sl);
len += sl;
};
auto append_freq_item = [&](float f, float mag) {
char tmp[64];
snprintf(tmp, sizeof(tmp), "\"%.0f\":%.6f", (double)f, (double)mag);
append_raw(tmp);
};
auto remove_trailing_comma = [&]() {
if (len > 0 && json_psram[len - 1] == ',') len--;
};
auto append_float = [&](const char* key, float val) {
char tmp[64];
snprintf(tmp, sizeof(tmp), ",\"%s\":%.6f", key, (double)val);
append_raw(tmp);
};
auto append_bool = [&](const char* key, bool v) {
char tmp[64];
snprintf(tmp, sizeof(tmp), ",\"%s\":%d", key, v ? 1 : 0);
append_raw(tmp);
};
auto append_int = [&](const char* key, long v) {
char tmp[64];
snprintf(tmp, sizeof(tmp), ",\"%s\":%ld", key, v);
append_raw(tmp);
};
// === X axis ===
append_raw("{\"x\":{");
if (b4r_esp_vibro_fft::_freqx && b4r_esp_vibro_fft::_magx) {
float* fx = (float*)b4r_esp_vibro_fft::_freqx->data;
float* mx = (float*)b4r_esp_vibro_fft::_magx->data;
int n = min(b4r_esp_vibro_fft::_freqx->length, b4r_esp_vibro_fft::_magx->length);
for (int i = 0; i < n; i++) {
if (fx[i] > 0.0f && mx[i] != 0.0f) {
append_freq_item(fx[i], mx[i]);
append_raw(",");
}
}
remove_trailing_comma();
}
append_raw("}");
// === Y axis ===
append_raw(",\"y\":{");
if (b4r_esp_vibro_fft::_freqy && b4r_esp_vibro_fft::_magy) {
float* fy = (float*)b4r_esp_vibro_fft::_freqy->data;
float* my = (float*)b4r_esp_vibro_fft::_magy->data;
int n = min(b4r_esp_vibro_fft::_freqy->length, b4r_esp_vibro_fft::_magy->length);
for (int i = 0; i < n; i++) {
if (fy[i] > 0.0f && my[i] != 0.0f) {
append_freq_item(fy[i], my[i]);
append_raw(",");
}
}
remove_trailing_comma();
}
append_raw("}");
// === Z axis ===
append_raw(",\"z\":{");
if (b4r_esp_vibro_fft::_freqz && b4r_esp_vibro_fft::_magz) {
float* fz = (float*)b4r_esp_vibro_fft::_freqz->data;
float* mz = (float*)b4r_esp_vibro_fft::_magz->data;
int n = min(b4r_esp_vibro_fft::_freqz->length, b4r_esp_vibro_fft::_magz->length);
for (int i = 0; i < n; i++) {
if (fz[i] > 0.0f && mz[i] != 0.0f) {
append_freq_item(fz[i], mz[i]);
append_raw(",");
}
}
remove_trailing_comma();
}
append_raw("}");
// RMS + temperature
append_float("rms_x", (float)b4r_esp_vibro_fft::_rmsx);
append_float("rms_y", (float)b4r_esp_vibro_fft::_rmsy);
append_float("rms_z", (float)b4r_esp_vibro_fft::_rmsz);
append_float("temperature", (float)b4r_esp_vibro_fft::_tmp);
// === All viban_* ===
append_float("viban_rotationfreq", (float)b4r_esp_vibro_fft::_viban_rotationfreq);
append_float("viban_rmsx", (float)b4r_esp_vibro_fft::_viban_rmsx);
append_float("viban_rmsy", (float)b4r_esp_vibro_fft::_viban_rmsy);
append_float("viban_rmsz", (float)b4r_esp_vibro_fft::_viban_rmsz);
append_bool("viban_xycorr", b4r_esp_vibro_fft::_viban_xycorr);
append_bool("viban_xzcorr", b4r_esp_vibro_fft::_viban_xzcorr);
....
append_raw("}"); // Close freq object
json_psram[len] = '\0';
if (b4r_esp_vibro_fft::_result) {
b4r_esp_vibro_fft::_result->data = (uint8_t*)json_psram;
b4r_esp_vibro_fft::_result->length = (int)len;
b4r_esp_vibro_fft::_psram_json_size = (int)len;
}
Serial.printf("JSON ready in PSRAM, size=%u\n", (unsigned)len);
}
// -----------------------------------------------------------------------------
// read_from_psram
// Reads a chunk from PSRAM into psramChunk (Byte array in B4R)
// Uses parameters _psram_read_start and _psram_read_len from B4R
// -----------------------------------------------------------------------------
B4R::Object* read_from_psram(B4R::Object* o) {
static B4R::Object ret;
int start = b4r_esp_vibro_fft::_psram_read_start;
int length = b4r_esp_vibro_fft::_psram_read_len;
Serial.printf("[read_from_psram] Chunk read request: start=%d length=%d json_psram=%p total_size=%d\n",
start, length, json_psram, b4r_esp_vibro_fft::_psram_json_size);
// Check parameter validity
if (!json_psram || start < 0 || length <= 0) {
b4r_esp_vibro_fft::_psramchunksize = 0;
Serial.println("[read_from_psram] ERROR: invalid parameters or json_psram not initialized!");
return ret.wrapNumber((Int)0);
}
// If start is beyond data — return 0
if (start >= b4r_esp_vibro_fft::_psram_json_size) {
b4r_esp_vibro_fft::_psramchunksize = 0;
Serial.printf("[read_from_psram] WARNING: start beyond data (start=%d, total=%d)\n",
start, b4r_esp_vibro_fft::_psram_json_size);
return ret.wrapNumber((Int)0);
}
// If requested length exceeds bounds — adjust
if (start + length > b4r_esp_vibro_fft::_psram_json_size) {
length = b4r_esp_vibro_fft::_psram_json_size - start;
Serial.printf("[read_from_psram] Adjusting chunk length: new_length=%d\n", length);
}
// Copy data from PSRAM to B4R buffer psramChunk
memcpy(b4r_esp_vibro_fft::_psramchunk->data, json_psram + start, length);
b4r_esp_vibro_fft::_psramchunksize = length;
// Log first bytes of chunk
Serial.printf("[read_from_psram] Chunk successfully copied: size=%d, first 60 chars: %.60s\n",
length, b4r_esp_vibro_fft::_psramchunk->data);
// Return length of read chunk
return ret.wrapNumber((Int)length);
}
#End If