Nextion NX4827P043 + esp32-wroom 32 +UDP data from game

Hi as said in the title Im trying to receive UDP packets from game (f1 codemasters game) with ESP32, and then show some of that info in the nextion screen.

So i have a "list" of points.

1-reveiving and extracto info from udp packets.
2-show some info in nextion screen.

point one was easy, i have a packet.h with the udp especification of f1 22 (https://github.com/hotlaps/f1-game-udp-specs/tree/main/2022)

Then, with wifiudp, i receive and parse packets.

int packetSize = Udp.parsePacket();
        if (packetSize > 0) {
          // read the packet into packetBufffer
          int packet_length = Udp.read(packetBuffer, sizeof(packetBuffer));
          if (packet_length >= sizeof(PacketHeader)) {
            struct PacketHeader * header = (struct PacketHeader * ) & packetBuffer;
            if (header -> m_packetFormat == 2022) {
              uint8_t myCar = header -> m_playerCarIndex;
              switch (header -> m_packetId) {
                case 2: {
                    struct PacketLapData * p;
                    p = (struct PacketLapData * ) packetBuffer;
                    struct LapData * lapdata = & (p -> m_lapData[myCar]);
                    lastLapTimeMS = lapdata -> m_lastLapTimeInMS;
                    currentLapTimeMS = lapdata -> m_currentLapTimeInMS;
                    sector1TimeMS = lapdata -> m_sector1TimeInMS;
                    sector2TimeMS = lapdata -> m_sector2TimeInMS;
                    lapDistance = lapdata -> m_lapDistance;
                    carPosition = lapdata -> m_carPosition;
                    currentLapNum = lapdata -> m_currentLapNum;
                    lapDelta = lastLapTimeMS - best;
                    if (lapDelta < 0) {
                      best = currentLapTimeMS;
                    }
                  }
                  break;

Also i have a rotary encoder to switch between pages.

The second part is driving me crazy.

I have configured baud=115200 on nextion editor. I have put

Serial2.begin(115200)

On setup().

And Im "writing" text like this:

unsigned int minutes = currentLapTimeMS / 60000;
unsigned int seconds = (int)(currentLapTimeMS % 60000)/1000;
unsigned int milliseconds = ((currentLapTimeMS % 60000)%1000);
Serial2.print(F("laptime.txt=\""));
Serial2.print(seconds);
Serial2.print(F("\""));
Serial2.print(F("\xFF\xFF\xFF"));

When printing "minutes" its alright. but, when printing seconds, it breaks (i have no tried to print milliseconds)

The textfield shows the correct value, then the next... but after some time, it stucks, and then after another few seconds, shows the correct value.

The game its configured with 60Hz UDP rate speed, but i have tried the lower value (10Hz) and nothing changes.

Its a speed problem? nextion/serial Can support a refresh rate to be able to change the text every millisecond? or every second?

And its also one textfield, in that screen will be 11, and a progressbar. If one textfield lags... its going to be a nightmare.

Any hints, or ideas?, im stuck...

edit:
This is all the code from the main program:

#include <WiFiUdp.h>
#include "NewEncoder.h"

#include <WiFi.h>

#include "Packets.h"
//Includes relacionados con el uso de la pantalla nextion

#include <SPI.h>

//Creamos objeto UDP
WiFiUDP Udp;

//Definición de constantes
#define MODE_LONG_RANGE_MODE 0x80
#define UDP_TX_PACKET_MAX_SIZE 6250

//Constantes UDP
const uint16_t F1_UDP_PORT = 20777;
uint8_t packetBuffer[UDP_TX_PACKET_MAX_SIZE];

//Datos conexión Wifi
const char * ssid = "xxxxxxxxxxx";
const char * password = "xxxxxxxxxx";

//Variables

int current = 0;
float best = 0;

//Variables nextio



void handleEncoder(void *pvParameters);
void ESP_ISR callBack(NewEncoder *encPtr, const volatile NewEncoder::EncoderState *state, void *uPtr);
QueueHandle_t encoderQueue;
volatile int16_t prevEncoderValue;

void setup() {
  Serial.begin(9600);
  Serial2.begin(115200);

  //Conectamos a la wifi
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("\nConectando");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(100);
  }

  //Mostramos la IP
  Serial.println("\nConectado a la wifi");
  Serial.print("Dirección IP: ");
  Serial.println(WiFi.localIP());

  BaseType_t success = xTaskCreatePinnedToCore(handleEncoder, "Handle Encoder", 1900, NULL, 2, NULL, 1);
  if (!success) {
    printf("Failed to create handleEncoder task. Aborting.\n");
    while (1) {
      yield();
    }
  }
  //Iniciamos la recepción UDP
  Udp.begin(F1_UDP_PORT);

}

void handleEncoder(void *pvParameters) {
  NewEncoder::EncoderState currentEncoderstate;
  int16_t currentValue;

  encoderQueue = xQueueCreate(1, sizeof(NewEncoder::EncoderState));
  if (encoderQueue == nullptr) {
    printf("Failed to create encoderQueue. Aborting\n");
    vTaskDelete(nullptr);
  }

  NewEncoder *encoder1 = new NewEncoder(26, 25, 0, 3, 0, FULL_PULSE);
  if (encoder1 == nullptr) {
    printf("Failed to allocate NewEncoder object. Aborting.\n");
    vTaskDelete(nullptr);
  }

  if (!encoder1->begin()) {
    printf("Encoder Failed to Start. Check pin assignments and available interrupts. Aborting.\n");
    delete encoder1;
    vTaskDelete(nullptr);
  }

  encoder1->getState(currentEncoderstate);
  prevEncoderValue = currentEncoderstate.currentValue;
  printf("Encoder Successfully Started at value = %d\n", prevEncoderValue);
  encoder1->attachCallback(callBack);

  for (;;) {
    xQueueReceive(encoderQueue, &currentEncoderstate, portMAX_DELAY);
    currentValue = currentEncoderstate.currentValue;
    if (currentValue != prevEncoderValue) {
      prevEncoderValue = currentValue;
      current = currentValue;
    } else {
      
    }
  }
  vTaskDelete(nullptr);
}

void ESP_ISR callBack(NewEncoder*encPtr, const volatile NewEncoder::EncoderState *state, void *uPtr) {
  BaseType_t pxHigherPriorityTaskWoken = pdFALSE;

  xQueueOverwriteFromISR(encoderQueue, (void * )state, &pxHigherPriorityTaskWoken);
  if (pxHigherPriorityTaskWoken) {
    portYIELD_FROM_ISR();
  }
}

void loop() {
  switch (current) {
    case 0: {

        uint32_t lastLapTimeMS;
        uint32_t currentLapTimeMS;
        float lapDistance;
        uint16_t sector1TimeMS;
        uint16_t sector2TimeMS;
        uint8_t carPosition;
        uint8_t currentLapNum;
        uint32_t lapDelta;
        uint16_t carSpeed;
        int8_t gear;
        uint8_t revLightsPercent;
        uint8_t tempRuedaDelanteIzq;
        uint8_t tempRuedaDetrasIzq;
        uint8_t tempRuedaDelanteDer;
        uint8_t tempRuedaDetrasDer;
        float vueltasGasolina;
        float porcentaje;
        uint16_t trackLength;
        struct * bestLap;
        struct * lastLap;
        float fuelLaps;
        int packetSize = Udp.parsePacket();
        if (packetSize > 0) {
          // read the packet into packetBufffer
          int packet_length = Udp.read(packetBuffer, sizeof(packetBuffer));
          if (packet_length >= sizeof(PacketHeader)) {
            struct PacketHeader * header = (struct PacketHeader * ) & packetBuffer;
            if (header -> m_packetFormat == 2022) {
              uint8_t myCar = header -> m_playerCarIndex;
              switch (header -> m_packetId) {
                case 2: {
                    struct PacketLapData * p;
                    p = (struct PacketLapData * ) packetBuffer;
                    struct LapData * lapdata = & (p -> m_lapData[myCar]);
                    lastLapTimeMS = lapdata -> m_lastLapTimeInMS;
                    currentLapTimeMS = lapdata -> m_currentLapTimeInMS;
                    sector1TimeMS = lapdata -> m_sector1TimeInMS;
                    sector2TimeMS = lapdata -> m_sector2TimeInMS;
                    lapDistance = lapdata -> m_lapDistance;
                    carPosition = lapdata -> m_carPosition;
                    currentLapNum = lapdata -> m_currentLapNum;
                    lapDelta = lastLapTimeMS - best;
                    if (lapDelta < 0) {
                      best = currentLapTimeMS;
                    }
                  }
                  break;
                case 6: {
                    struct PacketCarTelemetryData * p;
                    p = (struct PacketCarTelemetryData * ) packetBuffer;
                    struct CarTelemetryData * telemetry = & (p -> m_carTelemetryData[myCar]);
                    carSpeed = telemetry -> m_speed;
                    gear = telemetry -> m_gear;
                    revLightsPercent = telemetry -> m_revLightsPercent;
                    tempRuedaDelanteIzq = telemetry -> m_tyresSurfaceTemperature[2];
                    tempRuedaDetrasIzq = telemetry -> m_tyresSurfaceTemperature[0];
                    tempRuedaDelanteDer = telemetry -> m_tyresSurfaceTemperature[3];
                    tempRuedaDetrasDer = telemetry -> m_tyresSurfaceTemperature[1];
                  }
                  break;
                case 7: {
                    struct PacketCarStatusData * p;
                    p = (struct PacketCarStatusData * ) packetBuffer;
                    struct CarStatusData * status = & (p -> m_carStatusData[myCar]);
                    fuelLaps = status -> m_fuelRemainingLaps;
                    float ersStoreEnergy = status -> m_ersStoreEnergy;
                    float ersDeployedThisLap = status -> m_ersDeployedThisLap;
                    float ersHarvestedThisLapMGUK = status -> m_ersHarvestedThisLapMGUK;
                    float ersHarvestedThisLapMGUH = status -> m_ersHarvestedThisLapMGUH;
                    vueltasGasolina = status -> m_fuelRemainingLaps;
                    porcentaje = (ersStoreEnergy - ersDeployedThisLap + ersHarvestedThisLapMGUK + ersHarvestedThisLapMGUH) / ersStoreEnergy * 100;
                    if (porcentaje > 100) {
                      porcentaje = 100;
                    }
                  }
                  break;
                default:
                  break;
              }
              unsigned int minutes = currentLapTimeMS / 60000;
              unsigned int seconds = (int)(currentLapTimeMS % 60000)/1000;
              unsigned int milliseconds = ((currentLapTimeMS % 60000)%1000);
              Serial2.print(F("laptime.txt=\""));
              Serial2.print(seconds);
              Serial2.print(F("\""));
              Serial2.print(F("\xFF\xFF\xFF"));
            }
          }
        }
      }
      break;
    default:
      break;
  }

}

And this is packet.h

#pragma pack(push)
#pragma pack(1)


struct PacketHeader
{
  uint16_t      m_packetFormat;            // 2022
  uint8_t       m_gameMajorVersion;        // Game major version - "X.00"
  uint8_t       m_gameMinorVersion;        // Game minor version - "1.XX"
  uint8_t       m_packetVersion;           // Version of this packet type, all start from 1
  uint8_t       m_packetId;                // Identifier for the packet type, see below
  uint64_t      m_sessionUID;              // Unique identifier for the session
  float         m_sessionTime;             // Session timestamp
  uint32_t      m_frameIdentifier;         // Identifier for the frame the data was retrieved on
  uint8_t       m_playerCarIndex;          // Index of player's car in the array
  uint8_t       m_secondaryPlayerCarIndex; // Index of secondary player's car in the array (splitscreen)
  // 255 if no second player
};

struct LapData
{
  uint32_t    m_lastLapTimeInMS;              // Last lap time in milliseconds
  uint32_t    m_currentLapTimeInMS;           // Current time around the lap in milliseconds
  uint16_t    m_sector1TimeInMS;              // Sector 1 time in milliseconds
  uint16_t    m_sector2TimeInMS;              // Sector 2 time in milliseconds
  float       m_lapDistance;                  // Distance vehicle is around current lap in metres – could
  // be negative if line hasn’t been crossed yet
  float       m_totalDistance;                // Total distance travelled in session in metres – could
  // be negative if line hasn’t been crossed yet
  float       m_safetyCarDelta;               // Delta in seconds for safety car
  uint8_t     m_carPosition;                  // Car race position
  uint8_t     m_currentLapNum;                // Current lap number
  uint8_t     m_pitStatus;                    // 0 = none, 1 = pitting, 2 = in pit area
  uint8_t     m_numPitStops;                  // Number of pit stops taken in this race
  uint8_t     m_sector;                       // 0 = sector1, 1 = sector2, 2 = sector3
  uint8_t     m_currentLapInvalid;            // Current lap invalid - 0 = valid, 1 = invalid
  uint8_t     m_penalties;                    // Accumulated time penalties in seconds to be added
  uint8_t     m_warnings;                     // Accumulated number of warnings issued
  uint8_t     m_numUnservedDriveThroughPens;  // Num drive through pens left to serve
  uint8_t     m_numUnservedStopGoPens;        // Num stop go pens left to serve
  uint8_t     m_gridPosition;                 // Grid position the vehicle started the race in
  uint8_t     m_driverStatus;                 // Status of driver - 0 = in garage, 1 = flying lap
  // 2 = in lap, 3 = out lap, 4 = on track
  uint8_t     m_resultStatus;                 // Result status - 0 = invalid, 1 = inactive, 2 = active
  // 3 = finished, 4 = didnotfinish, 5 = disqualified
  // 6 = not classified, 7 = retired
  uint8_t     m_pitLaneTimerActive;           // Pit lane timing, 0 = inactive, 1 = active
  uint16_t    m_pitLaneTimeInLaneInMS;        // If active, the current time spent in the pit lane in ms
  uint16_t    m_pitStopTimerInMS;             // Time of the actual pit stop in ms
  uint8_t     m_pitStopShouldServePen;        // Whether the car should serve a penalty at this stop
};

struct PacketLapData
{
  PacketHeader    m_header;                 // Header

  LapData         m_lapData[22];            // Lap data for all cars on track

  uint8_t         m_timeTrialPBCarIdx;      // Index of Personal Best car in time trial (255 if invalid)
  uint8_t         m_timeTrialRivalCarIdx;   // Index of Rival car in time trial (255 if invalid)
};

struct CarDamageData
{
  float        m_tyresWear[4];                     // Tyre wear (percentage)
  uint8_t      m_tyresDamage[4];                   // Tyre damage (percentage)
  uint8_t      m_brakesDamage[4];                  // Brakes damage (percentage)
  uint8_t      m_frontLeftWingDamage;              // Front left wing damage (percentage)
  uint8_t      m_frontRightWingDamage;             // Front right wing damage (percentage)
  uint8_t      m_rearWingDamage;                   // Rear wing damage (percentage)
  uint8_t      m_floorDamage;                      // Floor damage (percentage)
  uint8_t      m_diffuserDamage;                   // Diffuser damage (percentage)
  uint8_t      m_sidepodDamage;                    // Sidepod damage (percentage)
  uint8_t      m_drsFault;                         // Indicator for DRS fault, 0 = OK, 1 = fault
  uint8_t      m_ersFault;                         // Indicator for ERS fault, 0 = OK, 1 = fault
  uint8_t      m_gearBoxDamage;                    // Gear box damage (percentage)
  uint8_t      m_engineDamage;                     // Engine damage (percentage)
  uint8_t      m_engineMGUHWear;                   // Engine wear MGU-H (percentage)
  uint8_t      m_engineESWear;                     // Engine wear ES (percentage)
  uint8_t      m_engineCEWear;                     // Engine wear CE (percentage)
  uint8_t      m_engineICEWear;                    // Engine wear ICE (percentage)
  uint8_t      m_engineMGUKWear;                   // Engine wear MGU-K (percentage)
  uint8_t      m_engineTCWear;                     // Engine wear TC (percentage)
  uint8_t      m_engineBlown;                      // Engine blown, 0 = OK, 1 = fault
  uint8_t      m_engineSeized;                     // Engine seized, 0 = OK, 1 = fault
};

struct PacketCarDamageData
{
  PacketHeader    m_header;               // Header

  CarDamageData   m_carDamageData[22];
};

struct CarTelemetryData
{
  uint16_t     m_speed;                       // Speed of car in kilometres per hour
  float        m_throttle;                    // Amount of throttle applied (0.0 to 1.0)
  float        m_steer;                       // Steering (-1.0 (full lock left) to 1.0 (full lock right))
  float        m_brake;                       // Amount of brake applied (0.0 to 1.0)
  uint8_t      m_clutch;                      // Amount of clutch applied (0 to 100)
  int8_t       m_gear;                        // Gear selected (1-8, N=0, R=-1)
  uint16_t     m_engineRPM;                   // Engine RPM
  uint8_t      m_drs;                         // 0 = off, 1 = on
  uint8_t      m_revLightsPercent;            // Rev lights indicator (percentage)
  uint16_t     m_revLightsBitValue;           // Rev lights (bit 0 = leftmost LED, bit 14 = rightmost LED)
  uint16_t     m_brakesTemperature[4];        // Brakes temperature (celsius)
  uint8_t      m_tyresSurfaceTemperature[4];  // Tyres surface temperature (celsius)
  uint8_t      m_tyresInnerTemperature[4];    // Tyres inner temperature (celsius)
  uint16_t     m_engineTemperature;           // Engine temperature (celsius)
  float        m_tyresPressure[4];            // Tyres pressure (PSI)
  uint8_t      m_surfaceType[4];              // Driving surface, see appendices
};

struct PacketCarTelemetryData
{
  PacketHeader           m_header;                          // Header

  CarTelemetryData       m_carTelemetryData[22];

  uint8_t                m_mfdPanelIndex;                   // Index of MFD panel open - 255 = MFD closed
  // Single player, race – 0 = Car setup, 1 = Pits
  // 2 = Damage, 3 =  Engine, 4 = Temperatures
  // May vary depending on game mode
  uint8_t                m_mfdPanelIndexSecondaryPlayer;    // See above
  int8_t                 m_suggestedGear;                   // Suggested gear for the player (1-8)
  // 0 if no gear suggested
};

struct CarSetupData
{
  uint8_t      m_frontWing;                // Front wing aero
  uint8_t      m_rearWing;                 // Rear wing aero
  uint8_t      m_onThrottle;               // Differential adjustment on throttle (percentage)
  uint8_t      m_offThrottle;              // Differential adjustment off throttle (percentage)
  float        m_frontCamber;              // Front camber angle (suspension geometry)
  float        m_rearCamber;               // Rear camber angle (suspension geometry)
  float        m_frontToe;                 // Front toe angle (suspension geometry)
  float        m_rearToe;                  // Rear toe angle (suspension geometry)
  uint8_t      m_frontSuspension;          // Front suspension
  uint8_t      m_rearSuspension;           // Rear suspension
  uint8_t      m_frontAntiRollBar;         // Front anti-roll bar
  uint8_t      m_rearAntiRollBar;          // Front anti-roll bar
  uint8_t      m_frontSuspensionHeight;    // Front ride height
  uint8_t      m_rearSuspensionHeight;     // Rear ride height
  uint8_t      m_brakePressure;            // Brake pressure (percentage)
  uint8_t      m_brakeBias;                // Brake bias (percentage)
  float        m_rearLeftTyrePressure;     // Rear left tyre pressure (PSI)
  float        m_rearRightTyrePressure;    // Rear right tyre pressure (PSI)
  float        m_frontLeftTyrePressure;    // Front left tyre pressure (PSI)
  float        m_frontRightTyrePressure;   // Front right tyre pressure (PSI)
  uint8_t      m_ballast;                  // Ballast
  float        m_fuelLoad;                 // Fuel load
};

struct PacketCarSetupData
{
  PacketHeader    m_header;            // Header

  CarSetupData    m_carSetups[22];
};

struct CarStatusData
{
  uint8_t       m_tractionControl;          // Traction control - 0 = off, 1 = medium, 2 = full
  uint8_t       m_antiLockBrakes;           // 0 (off) - 1 (on)
  uint8_t       m_fuelMix;                  // Fuel mix - 0 = lean, 1 = standard, 2 = rich, 3 = max
  uint8_t       m_frontBrakeBias;           // Front brake bias (percentage)
  uint8_t       m_pitLimiterStatus;         // Pit limiter status - 0 = off, 1 = on
  float         m_fuelInTank;               // Current fuel mass
  float         m_fuelCapacity;             // Fuel capacity
  float         m_fuelRemainingLaps;        // Fuel remaining in terms of laps (value on MFD)
  uint16_t      m_maxRPM;                   // Cars max RPM, point of rev limiter
  uint16_t      m_idleRPM;                  // Cars idle RPM
  uint8_t       m_maxGears;                 // Maximum number of gears
  uint8_t       m_drsAllowed;               // 0 = not allowed, 1 = allowed
  uint16_t      m_drsActivationDistance;    // 0 = DRS not available, non-zero - DRS will be available
  // in [X] metres
  uint8_t       m_actualTyreCompound;       // F1 Modern - 16 = C5, 17 = C4, 18 = C3, 19 = C2, 20 = C1
  // 7 = inter, 8 = wet
  // F1 Classic - 9 = dry, 10 = wet
  // F2 – 11 = super soft, 12 = soft, 13 = medium, 14 = hard
  // 15 = wet
  uint8_t       m_visualTyreCompound;       // F1 visual (can be different from actual compound)
  // 16 = soft, 17 = medium, 18 = hard, 7 = inter, 8 = wet
  // F1 Classic – same as above
  // F2 ‘19, 15 = wet, 19 – super soft, 20 = soft
  // 21 = medium , 22 = hard
  uint8_t       m_tyresAgeLaps;             // Age in laps of the current set of tyres
  int8_t        m_vehicleFiaFlags;          // -1 = invalid/unknown, 0 = none, 1 = green
  // 2 = blue, 3 = yellow, 4 = red
  float         m_ersStoreEnergy;           // ERS energy store in Joules
  uint8_t       m_ersDeployMode;            // ERS deployment mode, 0 = none, 1 = medium
  // 2 = hotlap, 3 = overtake
  float         m_ersHarvestedThisLapMGUK;  // ERS energy harvested this lap by MGU-K
  float         m_ersHarvestedThisLapMGUH;  // ERS energy harvested this lap by MGU-H
  float         m_ersDeployedThisLap;       // ERS energy deployed this lap
  uint8_t       m_networkPaused;            // Whether the car is paused in a network game
};

struct PacketCarStatusData
{
  PacketHeader      m_header;               // Header

  CarStatusData     m_carStatusData[22];
};

#pragma pack(pop)

The encoder part, its using a task, so it could run in the second core of esp32, avoiding interferences between main code and encoder interrupts. (if anyone has a better approach, im ok with erasing all and starting from scratch)

The only code i cant put is the tft code (for the nextion screen) but, its onle pages, textboxes and a bunch of images.

Always post the entire code. Know that every helper is a newbie facing Your project. The surrounding code provides help to get the big picture.
Split things into parts and attack one matter/issue at the time. Printing time to a display should not be any big problem. Try a simple test code just exercising the display. Use Serial.print and serial monitor to see what data there is.

@Railroader I have updated my OP with all code i have, its a little (or not so little...) messy... but im focused on getting all work, and then, cleaning a rewriting.

Good. Thanks.
But.... try to attack the small issues, one by one. If necessary, make a test code exercising just that part. Encoder, display, whatever. Take a step aside, send constants, dummies in communication, read devices etc. Use Serial.print and serial monitor. That was my help in my work during many years being the hired guy joining in like a fire brigade.


void setup() {
  Serial.begin(115200);
  Serial2.begin(115200);

}

void loop() {
  int minutes  = millis()/60000;
  int seconds = (millis()% 60000)/1000;
  int miliseconds = ((millis() % 60000)%1000);
  Serial2.print(F("t0.txt=\""));
  Serial2.print(minutes);
  Serial2.print(":");
  Serial2.printf("%02d",seconds);
  Serial2.print(".");
  Serial2.printf("%03d",miliseconds);
  Serial.println(seconds);
  Serial2.print(F("\""));
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);
}

I have tried that simple code, with baud=115200 also in nextion screen.

Works flawlessly .... so the refresh of screen or serial speed its not the problem.

I will try to get the udp package which contains the currentLapTimeMS and try again.

Thanks for the tip of "divide and win" @Railroader I will keep this thread updated with my progress.

Divide and win is used in all kinds of projects. You can imagine a moon landing craft. Smashing all parts together and presing the GO button it would likely not leave the launch pad.
Every little circuit is really tested a lot before adding it to the project. Overviewing a large project is hopeless.
Good luck!
Come back if You get stuck on anything.

Well, I have added udp stuff:

#include "Packets.h";
#include <WiFiUdp.h>
#include <WiFi.h>

#define MODE_LONG_RANGE_MODE 0x80
#define UDP_TX_PACKET_MAX_SIZE 3250

WiFiUDP Udp;

const uint16_t F1_UDP_PORT = 20777;
uint8_t packetBuffer[UDP_TX_PACKET_MAX_SIZE];

const char * ssid = "";
const char * password = "";

void setup() {
  Serial.begin(115200);
  Serial2.begin(115200);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("\nConectando");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(100);
  }

  Serial.println("\nConectado a la wifi");
  Serial.print("Dirección IP: ");
  Serial.println(WiFi.localIP());

  Udp.begin(F1_UDP_PORT);

}

void loop() {
  uint32_t LapTime;
  int packetSize = Udp.parsePacket();
  if (packetSize > 0) {
    // read the packet into packetBufffer
    int packet_length = Udp.read(packetBuffer, sizeof(packetBuffer));
    if (packet_length >= sizeof(PacketHeader)) {
      struct PacketHeader * header = (struct PacketHeader * ) & packetBuffer;
      if (header -> m_packetFormat == 2022) {
        uint8_t myCar = header -> m_playerCarIndex;
        switch (header -> m_packetId) {
          case 2: {
              struct PacketLapData * p;
              p = (struct PacketLapData * ) packetBuffer;
              struct LapData * lapdata = & (p -> m_lapData[myCar]);
              LapTime = lapdata ->m_currentLapTimeInMS;
              int minutes  = LapTime / 60000;
              int seconds = (LapTime % 60000) / 1000;
              int miliseconds = ((LapTime % 60000) % 1000);
              Serial2.print(F("t0.txt=\""));
              Serial2.print(minutes);
              Serial2.print(":");
              Serial2.printf("%02d", seconds);
              Serial2.print(".");
              Serial2.printf("%03d", miliseconds);
               Serial.print(minutes);
              Serial.print(":");
              Serial.printf("%02d", seconds);
              Serial.print(".");
              Serial.printf("%03d", miliseconds);
              Serial.println(seconds);
              Serial2.print(F("\""));
              Serial2.write(0xff);
              Serial2.write(0xff);
              Serial2.write(0xff);
            }
            break;
          default:
            break;
        }
      }
    }
  }
}

(the Packets.h is the same as in the first post)

Now its a bit laggy, in serial monitor and nextion screen. I have tested that its not ESP32 speed, nextion refresh or serial speed (because previous code works well) so now could be a wifi problem (I dont think is that) or UDP sending rate.

I have other apps (simdashboard, that installs and app on windows and other on android) and that value (currentlaptime) shows nice, so... Its not UDP speed or my wifi Speed...

Maybe ESP32 it's not powerful enough? or its wifi has something misconfigured?

EDIT: I fixed it, the problem is that i have set in f1 game to multicast udp, now i have set to send only packets to esp32, it worked, no more lag.

Im struggling again with this.

The f1 game sends a lot of packets, I can set an udp transmission of 60Hz, so some packets are send a that rate.

In my nextion,, i got the laptime, but, now, I tried to add the speed, which comes in another package.

There are 11 different types of packets, and the loop() needs to read every udp packet... some packets are sent 2 per second, or every 5 seconds, but only 4-5 of them. The rest are sent "as espcified in the game" so, at 60Hz rate. (or as low as 10Hz)

It means that esp32 will receive a lot of packets at the same time, but the loop only processes one at a time... or im confused? then.. a lot of packets will be discarded while the one picked is manipulated... And that means A LOT of packet loss...

Is there anyway to fix that? I have wrote an app in my laptop, in csharp, and it looks well... but my laptop is a i7and the arduino... its a "bit" slower xD

Is there any way to make a multithreaded loop? or to modifiy my code to be more efficient?

#include "Packets.h";
#include <WiFiUdp.h>
#include <WiFi.h>
#include "NewEncoder.h"

#define MODE_LONG_RANGE_MODE 0x80
#define UDP_TX_PACKET_MAX_SIZE 3250

WiFiUDP Udp;

const uint16_t F1_UDP_PORT = 20777;
uint8_t packetBuffer[UDP_TX_PACKET_MAX_SIZE];

const char * ssid = "";
const char * password = "";

int current = 0;
int anterior = 1;

void setup() {
  Serial.begin(115200);
  Serial2.begin(115200);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("\nConectando");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(100);
  }


  Serial.println("\nConectado a la wifi");
  Serial.print("Dirección IP: ");
  Serial.println(WiFi.localIP());
 
  Udp.begin(F1_UDP_PORT);

}


void loop() {
  if (current == 0 && current != anterior) {
    Serial2.print("page ");
    Serial2.print("Principal");
    Serial2.print("\xFF\xFF\xFF");
    anterior = current;
  } else  if (current == 1 && current != anterior) {
    Serial2.print("page ");
    Serial2.print("Damage");
    Serial2.print("\xFF\xFF\xFF");
    anterior = current;
  } else  if (current == 2 && current != anterior) {
    Serial2.print("page ");
    Serial2.print("Temperature");
    Serial2.print("\xFF\xFF\xFF");
    anterior = current;
  }  else  if (current == 3 && current != anterior) {
    Serial2.print("page ");
    Serial2.print("Engine");
    Serial2.print("\xFF\xFF\xFF");
    anterior = current;
  }
  int packetSize = Udp.parsePacket();
  if (packetSize > 0) {
    // read the packet into packetBufffer
    int packet_length = Udp.read(packetBuffer, sizeof(packetBuffer));
    if (packet_length >= sizeof(PacketHeader)) {
      struct PacketHeader * header = (struct PacketHeader * ) & packetBuffer;
      if (header -> m_packetFormat == 2022) {
        uint8_t myCar = header -> m_playerCarIndex;
        switch (header -> m_packetId) {
          case 2: {
              struct PacketLapData * p;
              p = (struct PacketLapData * ) packetBuffer;
              struct LapData * lapdata = & (p -> m_lapData[myCar]);
              uint32_t LapTime = lapdata ->m_currentLapTimeInMS;
              uint8_t Position = lapdata ->m_carPosition;
              uint8_t CurrentLap = lapdata ->m_currentLapNum;
              int minutes  = LapTime / 60000;
              int seconds = (LapTime % 60000) / 1000;
              int miliseconds = ((LapTime % 60000) % 1000);
              Serial2.print(F("laptime.txt=\""));
              Serial2.printf("%d:%02d.%03d \"", minutes, seconds, miliseconds);
              Serial2.print(F("\xFF\xFF\xFF"));
              Serial2.print(F("laps.txt=\"L"));
              Serial2.printf("%d\"", CurrentLap);
              Serial2.print(F("\xFF\xFF\xFF"));
              Serial2.print(F("position.txt=\"P"));
              Serial2.printf("%d\"", Position);
              Serial2.print(F("\xFF\xFF\xFF"));
            }
            break;
          case 6: {
              struct PacketCarTelemetryData * p;
              p = (struct PacketCarTelemetryData * ) packetBuffer;

              struct CarTelemetryData * telemetry = & (p -> m_carTelemetryData[myCar]);
              uint8_t tempRuedaDelanteIzqE = telemetry -> m_tyresSurfaceTemperature[2];
              uint8_t tempRuedaDetrasIzqE = telemetry -> m_tyresSurfaceTemperature[0];
              uint8_t tempRuedaDelanteDerE = telemetry -> m_tyresSurfaceTemperature[3];
              uint8_t tempRuedaDetrasDerE = telemetry -> m_tyresSurfaceTemperature[1];
              uint8_t tempRuedaDelanteIzqI = telemetry -> m_tyresInnerTemperature[2];
              uint8_t tempRuedaDetrasIzqI = telemetry -> m_tyresInnerTemperature[0];
              uint8_t tempRuedaDelanteDerI = telemetry -> m_tyresInnerTemperature[3];
              uint8_t tempRuedaDetrasDerI = telemetry -> m_tyresInnerTemperature[1];
              uint16_t tempFrenoDelanteIzq = telemetry -> m_brakesTemperature[2];
              uint16_t tempFrenoDetrasIzq = telemetry -> m_brakesTemperature[0];
              uint16_t tempFrenoDelanteDer = telemetry -> m_brakesTemperature[3];
              uint16_t tempFrenoDetrasDer = telemetry -> m_brakesTemperature[1];
              uint8_t tempEngine = telemetry -> m_engineTemperature;
              uint16_t velocidad = telemetry -> m_speed;
              //uint16_t leds = telemetry -> m_revLightsBitValue;
              uint8_t marcha = telemetry -> m_gear;
              if (current == 0) {
                temperaturaexterior("FLTT", tempRuedaDelanteIzqE);
                temperaturaexterior("RLTT", tempRuedaDetrasIzqE);
                temperaturaexterior("FRTT", tempRuedaDelanteDerE);
                temperaturaexterior("RRTT", tempRuedaDetrasDerE);
              }
              if (current == 2) {
                TemperaturaRuedasI("FILTT", "textITFL", tempRuedaDelanteIzqI, 233, 78, 79, 80);
                TemperaturaRuedasI("RILTT", "textITRL", tempRuedaDetrasIzqI, 233, 78, 79, 80);
                TemperaturaRuedasI("FIRTT", "textITFR", tempRuedaDelanteDerI, 233, 78, 79, 80);
                TemperaturaRuedasI("RIRTT", "textITRR", tempRuedaDetrasDerI, 233, 78, 79, 80);

                TemperaturaRuedasE("FELTT", "textETFL", tempRuedaDelanteIzqE, 235, 81, 82, 83);
                TemperaturaRuedasE("RELTT", "textETRL", tempRuedaDetrasIzqE, 235, 81, 82, 83);
                TemperaturaRuedasE("FERTT", "textETFR", tempRuedaDelanteDerE, 235, 81, 82, 83);
                TemperaturaRuedasE("RERTT", "textETRR", tempRuedaDetrasDerE, 235, 81, 82, 83);

                TemperaturaFrenos("FBLTT", "textBFL", tempFrenoDelanteIzq, 234, 84, 85, 86);
                TemperaturaFrenos("RBLTT", "textBRL", tempFrenoDetrasIzq, 234, 84, 85, 86);
                TemperaturaFrenos("FBRTT", "textBFR", tempFrenoDelanteDer, 234, 84, 85, 86);
                TemperaturaFrenos("RBRTT", "textBRR", tempFrenoDetrasDer, 234, 84, 85, 86);

                RuedasTempI ("FLITemp", tempRuedaDelanteIzqI, 62, 63, 64, 65, 66);
                RuedasTempI ("RLITemp", tempRuedaDetrasIzqI, 62, 63, 64, 65, 66);
                RuedasTempI ("FRITemp", tempRuedaDelanteDerI, 62, 63, 64, 65, 66);
                RuedasTempI ("RRITemp", tempRuedaDetrasDerI, 62, 63, 64, 65, 66);

                RuedasTempE ("FLETemp", tempRuedaDelanteIzqE, 67, 68, 69, 70, 71);
                RuedasTempE ("RLETemp", tempRuedaDetrasIzqE, 67, 68, 69, 70, 71);
                RuedasTempE ("FRETemp", tempRuedaDelanteDerE, 67, 68, 69, 70, 71);
                RuedasTempE ("RRETemp", tempRuedaDetrasDerE, 67, 68, 69, 70, 71);

                FrenosTemp ("FLBT", tempFrenoDelanteIzq, 52, 53, 54, 55, 56, 57);
                FrenosTemp ("RLBT", tempFrenoDetrasIzq, 52, 53, 54, 55, 56, 57);
                FrenosTemp ("FRBT", tempFrenoDelanteDer, 52, 53, 54, 55, 56, 57);
                FrenosTemp ("RRBT", tempFrenoDetrasDer, 52, 53, 54, 55, 56, 57);

                tempMotor("iconICETEMP", "ICETEMP", tempEngine, 72, 73, 74, 75, 76, 77);
              }
              
              if (current == 0) {
                Serial2.print(F("speed.txt=\""));
                Serial2.printf("%d \"" , velocidad);
                Serial2.print(F("\xFF\xFF\xFF"));
                Serial2.print(F("gear.txt=\""));
                if (marcha > 0 & marcha < 9) {
                  Serial2.printf("%d \"" , marcha);
                } else if ( marcha == 0) {
                  Serial2.print("N\"");
                } else if ( marcha == 255) {
                  Serial2.print("R\"");
                }
                Serial2.print(F("\xFF\xFF\xFF"));
              }
            }
            break;
          case 7: {
              struct PacketCarStatusData * p;
              p = (struct PacketCarStatusData * ) packetBuffer;
              struct CarStatusData * status = & (p -> m_carStatusData[myCar]);
              float fuel = status -> m_fuelRemainingLaps;
              float ERS = status -> m_ersStoreEnergy;
              float ERStatus = status ->m_ersDeployMode;
              if (current == 0) {
                Serial2.print(F("lapsdelta.txt=\""));
                if (fuel > 0) {
                  Serial2.printf("(%.2f) \"" , fuel);
                  Serial2.print(F("\xFF\xFF\xFF"));
                  Serial2.print(F("lapsdelta.pco=2016"));
                  Serial2.print(F("\xFF\xFF\xFF"));
                } else {
                  Serial2.printf("(%.2f) \"" , fuel);
                  Serial2.print(F("\xFF\xFF\xFF"));

                  Serial2.print(F("lapsdelta.pco=63488"));
                  Serial2.print(F("\xFF\xFF\xFF"));
                }
                float porcentaje = (ERS / 4000000) * 100;
                Serial2.print(F("ERST.txt=\""));
                Serial2.printf("%.0f%% \"" , porcentaje);
                Serial2.print(F("\xFF\xFF\xFF"));
                Serial2.print(F("ERSBar.val="));
                Serial2.printf("%.0f" , porcentaje);
                Serial2.print(F("\xFF\xFF\xFF"));
                if (porcentaje > 20) {
                  Serial2.print(F("ERSBar.pco=65504"));
                  Serial2.print(F("\xFF\xFF\xFF"));
                } else {
                  Serial2.print(F("ERSBar.pco=63488"));
                  Serial2.print(F("\xFF\xFF\xFF"));
                }
                if (ERStatus == 3) {
                  Serial2.print(F("ERSACT.bco=2016"));
                  Serial2.print(F("\xFF\xFF\xFF"));
                } else {
                  Serial2.print(F("ERSACT.bco=64800"));
                  Serial2.print(F("\xFF\xFF\xFF"));
                }
              }
            } break;
          case 10: {
              struct PacketCarDamageData * p;
              p = (struct PacketCarDamageData * ) packetBuffer;
              struct CarDamageData * CarDamage = & (p -> m_carDamageData[myCar]);
              float FLTW = CarDamage -> m_tyresWear[2];
              float RLTW = CarDamage -> m_tyresWear[0];
              float FRTW = CarDamage -> m_tyresWear[3];
              float RRTW = CarDamage -> m_tyresWear[1];
              uint8_t FLTD = CarDamage -> m_tyresDamage[2];
              uint8_t RLTD = CarDamage -> m_tyresDamage[0];
              uint8_t FRTD = CarDamage -> m_tyresDamage[3];
              uint8_t RRTD = CarDamage -> m_tyresDamage[1];
              uint8_t FLBD = CarDamage -> m_brakesDamage[2];
              uint8_t RLBD = CarDamage -> m_brakesDamage[0];
              uint8_t FRBD = CarDamage -> m_brakesDamage[3];
              uint8_t RRBD = CarDamage -> m_brakesDamage[1];
              uint8_t FLWD = CarDamage -> m_frontLeftWingDamage;
              uint8_t FRWD = CarDamage -> m_frontRightWingDamage;
              uint8_t RWD = CarDamage -> m_rearWingDamage;
              uint8_t FloorD = CarDamage -> m_floorDamage;
              uint8_t DiffuD = CarDamage -> m_diffuserDamage;
              uint8_t SidePodD = CarDamage -> m_sidepodDamage;
              uint8_t GearBoxD = CarDamage -> m_gearBoxDamage;
              uint8_t MciD = CarDamage -> m_engineDamage;
              uint8_t MGUHW = CarDamage -> m_engineMGUHWear;
              uint8_t ESW = CarDamage -> m_engineESWear;
              uint8_t CEW = CarDamage -> m_engineCEWear;
              uint8_t MCIW = CarDamage -> m_engineICEWear;
              uint8_t MGUKW = CarDamage -> m_engineMGUKWear;
              uint8_t TCW = CarDamage -> m_engineTCWear;
              uint8_t GBW = CarDamage -> m_gearBoxDamage;
              if (current == 3) {
                desgasteMotor("mguhv", "der", MGUHW, 114, 115, 116, 117, 118, 119);
                desgasteMotor("esv", "arri", ESW, 90, 91, 92, 93, 94, 95);
                desgasteMotor("cev", "chal", CEW, 108, 109, 110, 111, 112, 113);
                desgasteMotor("mciv", "centro", MCIW, 102, 103, 104, 105, 106, 107);
                desgasteMotor("mgukv", "izq", MGUKW, 120, 121, 122, 123, 124, 125);
                desgasteMotor("tcv", "turbo", TCW, 126, 127, 128, 129, 130, 131);
                desgasteMotor("gearv", "GB", GBW, 96, 97, 98, 99, 100, 101);
              }
              if (current == 1) {
                desgasteneumaticos("indFLD", FLTW);
                desgasteneumaticos("indRLD", RLTW);
                desgasteneumaticos("indFRD", FRTW);
                desgasteneumaticos("indRRD", RRTW);

                danoCocheFW("FLT", FLTD, 27, 28, 29, 30, 31);
                danoCocheFW("RLT", RLTD, 27, 28, 29, 30, 31);
                danoCocheFW("FRT", FRTD, 27, 28, 29, 30, 31);
                danoCocheFW("RRT", RRTD, 27, 28, 29, 30, 31);

                danoCocheFW("FLBD", FLBD, 53, 54, 55, 56, 57);
                danoCocheFW("RLBD", RLBD, 53, 54, 55, 56, 57);
                danoCocheFW("FRBD", FRBD, 53, 54, 55, 56, 57);
                danoCocheFW("RRBD", RRBD, 53, 54, 55, 56, 57);

                danoCocheFW("FWRD", FRWD, 11, 12, 13, 14, 15);
                danoCocheFW("FWLD", FLWD, 6, 7, 8, 9, 10);
                danoCocheFW("floor", FloorD, 1, 2, 3, 4, 5);
                danoCocheFW("SPI", SidePodD, 37, 38, 39, 40, 41);
                danoCocheFW("SDP", SidePodD, 42, 43, 44, 45, 46);
                danoCocheFW("Diff", DiffuD, 21, 22, 23, 24, 25);
                danoCocheFW("RW", RWD, 32, 33, 34, 35, 36);
                danoCocheFW("ICED", MciD, 16, 17, 18, 19, 20);
                danoCocheFW("CCD", GearBoxD, 47, 48, 49, 50, 51);
              }
            } break;


          default:
            break;
        }
      }
    }
  }
}

packet.h is something like this:

#pragma pack(push)
#pragma pack(1)


struct PacketHeader
{
  uint16_t      m_packetFormat;            // 2022
  uint8_t       m_gameMajorVersion;        // Game major version - "X.00"
  uint8_t       m_gameMinorVersion;        // Game minor version - "1.XX"
  uint8_t       m_packetVersion;           // Version of this packet type, all start from 1
  uint8_t       m_packetId;                // Identifier for the packet type, see below
  uint64_t      m_sessionUID;              // Unique identifier for the session
  float         m_sessionTime;             // Session timestamp
  uint32_t      m_frameIdentifier;         // Identifier for the frame the data was retrieved on
  uint8_t       m_playerCarIndex;          // Index of player's car in the array
  uint8_t       m_secondaryPlayerCarIndex; // Index of secondary player's car in the array (splitscreen)
  // 255 if no second player
};

struct LapData
{
  uint32_t    m_lastLapTimeInMS;              // Last lap time in milliseconds
  uint32_t    m_currentLapTimeInMS;           // Current time around the lap in milliseconds
  uint16_t    m_sector1TimeInMS;              // Sector 1 time in milliseconds
  uint16_t    m_sector2TimeInMS;              // Sector 2 time in milliseconds
  float       m_lapDistance;                  // Distance vehicle is around current lap in metres – could
  // be negative if line hasn’t been crossed yet
  float       m_totalDistance;                // Total distance travelled in session in metres – could
  // be negative if line hasn’t been crossed yet
  float       m_safetyCarDelta;               // Delta in seconds for safety car
  uint8_t     m_carPosition;                  // Car race position
  uint8_t     m_currentLapNum;                // Current lap number
  uint8_t     m_pitStatus;                    // 0 = none, 1 = pitting, 2 = in pit area
  uint8_t     m_numPitStops;                  // Number of pit stops taken in this race
  uint8_t     m_sector;                       // 0 = sector1, 1 = sector2, 2 = sector3
  uint8_t     m_currentLapInvalid;            // Current lap invalid - 0 = valid, 1 = invalid
  uint8_t     m_penalties;                    // Accumulated time penalties in seconds to be added
  uint8_t     m_warnings;                     // Accumulated number of warnings issued
  uint8_t     m_numUnservedDriveThroughPens;  // Num drive through pens left to serve
  uint8_t     m_numUnservedStopGoPens;        // Num stop go pens left to serve
  uint8_t     m_gridPosition;                 // Grid position the vehicle started the race in
  uint8_t     m_driverStatus;                 // Status of driver - 0 = in garage, 1 = flying lap
  // 2 = in lap, 3 = out lap, 4 = on track
  uint8_t     m_resultStatus;                 // Result status - 0 = invalid, 1 = inactive, 2 = active
  // 3 = finished, 4 = didnotfinish, 5 = disqualified
  // 6 = not classified, 7 = retired
  uint8_t     m_pitLaneTimerActive;           // Pit lane timing, 0 = inactive, 1 = active
  uint16_t    m_pitLaneTimeInLaneInMS;        // If active, the current time spent in the pit lane in ms
  uint16_t    m_pitStopTimerInMS;             // Time of the actual pit stop in ms
  uint8_t     m_pitStopShouldServePen;        // Whether the car should serve a penalty at this stop
};

But with all packets, its just a demo of all of them, i thinks is useless to put all.

and al the functions called inside de switch are only functions like:

void RuedasTempE(const char * elemento, int valor, int a, int b, int c, int d, int e) {
  if (valor < 56) {
    Serial2.printf("%s.pic=%d", elemento, a);
  } else if (valor < 125) {
    Serial2.printf("%s.pic=%d", elemento, b);
  } else if (valor < 135) {
    Serial2.printf("%s.pic=%d", elemento, c);
  }  else if (valor < 140) {
    Serial2.printf("%s.pic=%d", elemento, d);
  } else {
    Serial2.printf("%s.pic=%d", elemento, e);
  }
  Serial2.print(F("\xFF\xFF\xFF"));
}

that behavior was mitigated with those if inside every case, to avoid processing packets if the page is not using them. but... it doesnt fix the problem about receiving a bunch of packets at same time.

Important to say, even without all the nextion stuff (printing on serial monitor) it keeps losing info.

PS: the encoder stuff and current var are there for an encoder to change between pages, just ignore them.

So, the question is, is a coding problem, or the esp32 cant be used for this due to its speed?

thanks. if any other info is needed, ask... but thats almost all the code

EDIT:

I have tried to put one by one, using only for example, case 6. its laggy, i think that other packages are sent more often, so its a matter of luck to manipulate that packet...

1 Like

For analysing the situation I would comment out all the serial printing and use an array of unsigned longs to store timestamps of function micros()

Let the loop run until the array is filled then print the difference of the timestamps
stamp[1] - stamp[0] calculates the execution time of the first iteration
stamp[2] - stamp[1] calculates the execution time of the seconditeration
etc.

This will show you how much time it needs to run through loop()

then this can be more detailed by more timestamps along function loop()
and/or how long it takes for different messages

best regards Stefan

295
197
274
219
400
168
186
191
57
427
165
168
174
50
47
47
47

I have put a micros() at first line in loop, another at the end.

the worst case (without any serial2.print and any call to functions, just receive a decode the packets) takes 400 micros.

Then i have repeated the same, but with all code:

10677
195
10817
10807
182
10730
10846
404
208
10798
178
10563
183
160
469
10879
10763
10759
10772
182
10537

Thats a huge difference...

sometimes it takes 0,011s to loop.

As there are packets that are bigger than others (from 40 bytes, to 1400 bytes but the most of them are bigger than 1000 bytes) that explains the differences at looping...

But its 0,011s insufficient?

5 packets are sent "as rate set in menus" thats 60Hz so 5 packets 60 times every second, thats 300 packets ever second... or 0.0033s/packet

If im not mistaken, that loop is slower than the rate. Using 10Hz ""solves"" that problem, but now the info is lagging... but because is sent less often.

I have wrote a c# app, and put it on a raspberry pi 4. Smooth. Maybe i should discard arduino and go to that... just need to know how to use the nextion screen with c#...

https://www.google.com/search?as_q=serial+communication+c%23

Or maybe you use a teensy 4.0 / 4.1
https://www.pjrc.com/store/teensy40.html

best regards Stefan

1 Like

Hmm im stuck.

  SerialPort serialPort = new SerialPort("/dev/ttyS0", 115200, Parity.None, 8, StopBits.One);
  serialPort.Handshake = Handshake.None;
  serialPort.Open();
  // Write the data to the serial port
  string s = string.Format("laptime.txt=\"{0}:{1}.{2}\"\0xff\0xff\0xff", minutes, seconds, miliseconds);
  byte[] byteArray = Encoding.UTF8.GetBytes(s);
  Console.WriteLine("Sending: " + s); // Debug print
  serialPort.Write(s);

Console line writes:

Sending: laptime.txt="18:13.867"xffxffxff

But the nextion does nothing.

maybe @PerryBebbington could know whats happening since he wrote a nextion tutorial.

edit: fixed

string s = string.Format("laptime.txt=\"{0}:{1}.{2}\"", minutes, seconds, miliseconds);

byte[] commandBytes = Encoding.Default.GetBytes(s);
byte[] terminatorBytes = new byte[] { 0xFF, 0xFF, 0xFF };
byte[] combinedBytes = commandBytes.Concat(terminatorBytes).ToArray();
serialPort.Write(combinedBytes, 0, combinedBytes.Length);

Sure, but nowhere do I use Strings (capital S), I always use C strings, AKA null terminated char arrays. If you search this forum then hopefully you will find the neverending debate about the benefits and pitfalls of Strings and C strings; I'm not going to start that debate here, just bring it to your attention.

Okay, good :smiley:
Thank you for the update.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.