I would need Help make this thing work again

e-Paper display, it is working perfect since 2022, but I wanted to update the guns/pellets libraries with new stuff...

I made a mistake and let the arduino update, also updated all libraries as well. Also my discord login expired some time ago.... hard to expect collecting people from the original development team.
My problem is that I am not a coder, I had some learning curve in the past but have not use it in past two or so years, so now I am stuck with lack of knowledge what and where to look for.

These are the error message when I want to Verify or Start Debugging:

error compiling

I cannot - new user - upload attachments (*ino), that can go by pm or email?

Those error messages are useless without the code that caused them.

Please don't post screenshots of text. That makes it nearly impossible to read. It's just useless. Copy and paste the text so that someone might stand a chance of helping you.

Post links to this project. You can't assume that we were all there in development with you and just know all about it. There are people who will take a look and try to help, but you have to give them something to look at.

You was faster then me editing the OP...
Copy pasting the *.ino would be a long text to scroll, over 1250 lines.
Any other way around?

btw, howto - "post link to this project" - on my PC?

Let me see if dropbox link can work (as download only):
https://www.dropbox.com/scl/fi/fkpuk8zcuifq3ysalvuoh/FXChrony_TTGO_v1.1_EINK_V2.ino?rlkey=v9b85ofg4yt2b1ud59a7e06mn&st=ewzl6j2t&dl=0

The error message from Verifying:
Compilation error: 'adc1_config_width' was not declared in this scope

The error message from Debugging:
File not found "executable": "C:/Users\Attila\AppData\Local\Temp\arduino\sketches\83AF22CAD977C7B2896C29E28FD39BE0\FXChrony_TTGO_v1.1_EINK_V2.ino.elf"

For a short piece of code like that just post it. That's the easiest way for people to be able to look at it.

An error occurred: Sorry, new users can only put 4 links in a post.

This is a reason I placed the file in dropbox.

Also, I don't know how to preformat

pre - format

#include <GxEPD.h>
#include "BLEDevice.h"
#include "OneButton.h"
#include <EEPROM.h>
#include <esp_sleep.h>
#include "esp_adc_cal.h"
#include "pellet.h"
#include "gun.h"
#include "FX.h"

#include <GxDEPG0213BN/GxDEPG0213BN.h>    // 2.13" b/w 128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1

#include GxEPD_BitmapExamples

// FreeFonts from Adafruit_GFX
#include <Fonts/FreeMonoBold9pt7b.h>
#include <Fonts/FreeMonoBold12pt7b.h>
#include <Fonts/FreeMonoBold18pt7b.h>
#include <Fonts/FreeMonoBold24pt7b.h>
#include <Fonts/FreeSans9pt7b.h>
#include <Fonts/FreeSans12pt7b.h>
#include <Fonts/FreeSansBold9pt7b.h>
#include <Fonts/FreeSansBold12pt7b.h>
#include <Fonts/FreeSansBold18pt7b.h>
#include <Fonts/FreeSansBold24pt7b.h>
//#include <Fonts/FreeSans24pt7b.h>
#include <GxIO/GxIO_SPI/GxIO_SPI.h>
#include <GxIO/GxIO.h>

// for SPI pin definitions see e.g.:
// C:\Users\xxx\Documents\Arduino\hardware\espressif\esp32\variants\lolin32\pins_arduino.h

GxIO_Class io(SPI, /*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16); // arbitrary selection of 17, 16
GxEPD_Class display(io, /*RST=*/ 16, /*BUSY=*/ 4); // arbitrary selection of (16), 4

const uint8_t Whiteboard[1700] = {0x00};

typedef enum
{
    RIGHT_ALIGNMENT = 0,
    LEFT_ALIGNMENT,
    CENTER_ALIGNMENT,
} Text_alignment;


/* 
 * For Minimum, Average, Maximum change MIN_AVE_MAX from 0 to 1 
 * For ES/SD leave MIN_AVE_MAX at 0
 */
#define MIN_AVE_MAX 0



#define SHOT_STRING_LENGTH  20
// [0] = shot string length
// [1] = pellet_idx
// SHOT_STRING_LENGTH * shots
#define EEPROM_PER_GUN (SHOT_STRING_LENGTH * sizeof(float) + 2)
#define EEPROM_SIZE (6 + EEPROM_PER_GUN * NUM_GUNS)

static esp_adc_cal_characteristics_t adc_chars;

#define PIN_INPUT 39
OneButton button(PIN_INPUT, true);

#define UNITS_IMPERIAL  0
#define UNITS_METRIC    1
#define UNITS_MAX       1

#define DISPLAY_FLIP_OFF    0
#define DISPLAY_FLIP_ON     1
#define DISPLAY_FLIP_MAX    1

#define SENSITIVITY_MAX     100

#define STATE_IDLE          0
#define STATE_CONNECTING    1
#define STATE_CONNECTED     2
#define STATE_OFFLINE       3

#define seconds() (millis()/1000)

static uint8_t state = STATE_IDLE;

static float chronyVBattery;
static unsigned long chronyVBattLastRead = 0;

// The remote service we wish to connect to.
static BLEUUID deviceUUID("0000180a-0000-1000-8000-00805f9b34fb");

static BLEUUID serviceUUID("00001623-88EC-688C-644B-3FA706C0BB75");

// The characteristic of the remote service we are interested in.
static const char * charUUIDs[] = {
  "00001624-88EC-688C-644B-3FA706C0BB75",
  "00001625-88EC-688C-644B-3FA706C0BB75",
  "00001626-88EC-688C-644B-3FA706C0BB75",
  "00001627-88EC-688C-644B-3FA706C0BB75",
  "00001628-88EC-688C-644B-3FA706C0BB75",
  "00001629-88EC-688C-644B-3FA706C0BB75",
  "0000162A-88EC-688C-644B-3FA706C0BB75"
};

static BLERemoteCharacteristic* pRemoteCharacteristic;
static BLEAdvertisedDevice* myDevice;
static BLEClient*  pClient;
static BLERemoteService* pRemoteService;

static bool renderMenu = false;
static bool dirty = false;
static bool profile_changed = false;
static bool power_saving = false;
static unsigned long display_on_at = 0;
static uint8_t searching_ctr = 0;

static uint8_t sensitivity = 50;
static uint8_t units = UNITS_IMPERIAL;

static uint8_t display_flip = 1;
static uint8_t power_save_duration = 0;
static uint8_t gun_index = 0;

static uint8_t nc_counter = 0;

typedef  void (* menuItemCallback_t)(uint8_t);
typedef  void (* menuItemGenString_t)(uint8_t, char *);

typedef struct shot_stats {
  float min;
  float max;
  float avg;
  float es;
  float sd;
} shot_stats_t;

typedef struct menuItem {
    const char * menuString;
    menuItemGenString_t menuItemGenString;
    struct menuItem * nextMenuItem;
    struct menuItem * currentSubMenu;
    struct menuItem * subMenu;
    menuItemCallback_t menuItemCallback;
    uint8_t param;
    menuItemGenString_t menuItemGenCurSelString;
} menuItem_t;

static menuItem_t * menu_gun = NULL;
static menuItem_t * menu_pellet = NULL;
static menuItem_t * menuStack[4];
static int menuStackIndex;
static menuItem_t * pCurrentMenuItem;

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
  }

  void onDisconnect(BLEClient* pclient) {
    /* this make me sad, can't get the code to reliably reconnect 
    more than 4-5 times so here it is ... 
    (On the plus side it seems to work well and I can get 
    on with shot strings :) )*/
    ESP.restart();
    while(1){}
  }
};


void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.println("setup");

  display.init(); // enable diagnostic output on Serial

  display.setRotation(1);
  display.fillScreen(GxEPD_WHITE);
  display.setFont(&FreeMonoBold9pt7b);
  display.setTextColor(GxEPD_BLACK);
  display.drawRoundRect(0, 6, 250, 122, 10, GxEPD_BLACK);
  //display.updateWindow(0, 0,  250,  128, true);
  display.update();

  Serial.println("setup done");


  button.attachDoubleClick(doubleClick);
  button.attachLongPressStart(longPressStop);
  button.attachClick(singleClick);
  
  adc1_config_width(ADC_WIDTH_BIT_12);
  adc1_config_channel_atten(ADC1_CHANNEL_1, ADC_ATTEN_DB_11);
  esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1100, &adc_chars);
  pinMode(14, OUTPUT);
  digitalWrite(14, HIGH);

/*
 * Read the Settings, if any setting is out of range
 * give it a sensible default value (cope with first use)
 */
  
  EEPROM.begin(EEPROM_SIZE);
  sensitivity = EEPROM.read(0);
  if(sensitivity > SENSITIVITY_MAX) {
    sensitivity = 30;
    EEPROM.write(0, sensitivity);    
  }
  units = EEPROM.read(1);
  if(units > UNITS_MAX) {
    units = UNITS_MAX;
    EEPROM.write(1, units);
  }
  gun_index = EEPROM.read(2);
  if(gun_index >= NUM_GUNS) {
    gun_index = 0;
    EEPROM.write(2, gun_index);
  }
  display_flip = EEPROM.read(3);
  if(display_flip > DISPLAY_FLIP_MAX) {
    display_flip = 0;
    EEPROM.write(3, display_flip);
  }
  power_save_duration = EEPROM.read(4);
  if(power_save_duration > 60) {
    power_save_duration = 60;
    EEPROM.write(4, power_save_duration);
  }
  EEPROM.commit();

  BLEDevice::init("");

  build_gun_menu();

  dirty = true;
}

uint8_t get_string_length(uint8_t gidx) {
  return EEPROM.read(6 + (gidx * EEPROM_PER_GUN));
}

void clear_string(uint8_t gidx) {
  EEPROM.write(6 + (gidx * EEPROM_PER_GUN), 0);
  EEPROM.commit();
}

float get_shot(uint8_t gidx, uint8_t sidx) {
  float result;
  EEPROM.get(6 + (gidx * EEPROM_PER_GUN) + sidx * sizeof(float) + 2, result);
  return result;
}

void add_shot(uint8_t gidx, float speed) {
  uint8_t sidx = get_string_length(gidx);
  
  if(sidx >= my_guns[gun_index].shot_string_length) {
    clear_string(gidx);
    sidx = 0;
  }
  EEPROM.put(6 + (gidx * EEPROM_PER_GUN) + sidx * sizeof(float) + 2, speed);
  EEPROM.write(6 + (gidx * EEPROM_PER_GUN), sidx + 1);
  EEPROM.commit();
}

uint8_t get_pellet_index(uint8_t gidx) 
{
  return EEPROM.read(6 + (gidx * EEPROM_PER_GUN) + 1);
}

void set_pellet_index(uint8_t gidx, uint8_t pidx) 
{
  EEPROM.write(6 + (gidx * EEPROM_PER_GUN) + 1, pidx);
  EEPROM.commit();
  get_pellet_index(gidx); 
}

void doRenderMenu() {
  char genHeader[256];


  int16_t x = 0;
  int16_t y = 0;
  int16_t x1, y1;
  uint16_t w, h;


  display.fillScreen(GxEPD_WHITE);
  display.drawRoundRect(0, 6, 250, 122, 10, GxEPD_BLACK);


  const char * pHeadertxt;
  if(pCurrentMenuItem->menuItemGenString == NULL) {
    pHeadertxt = pCurrentMenuItem->menuString;
  } else {
      pHeadertxt = genHeader;
      pCurrentMenuItem->menuItemGenString(pCurrentMenuItem->currentSubMenu->param, genHeader);
  }

  display.setFont(&FreeSansBold12pt7b);
  printThis( 0, 40, pHeadertxt, CENTER_ALIGNMENT);

  const char * psubHeadertxt = pCurrentMenuItem->currentSubMenu->menuString;
  if(psubHeadertxt == NULL) {
      psubHeadertxt = genHeader;
      pCurrentMenuItem->currentSubMenu->menuItemGenString(pCurrentMenuItem->currentSubMenu->param, genHeader);
  }

  display.getTextBounds(psubHeadertxt, x, y, &x1, &y1, &w, &h);
    printThis( 0, 80, psubHeadertxt, CENTER_ALIGNMENT);

  const char * pcurSelHeadertxt;
  if(pCurrentMenuItem->currentSubMenu->menuItemGenCurSelString) {
      pcurSelHeadertxt = genHeader;
      pCurrentMenuItem->currentSubMenu->menuItemGenCurSelString(pCurrentMenuItem->currentSubMenu->param, genHeader);

      display.getTextBounds(pcurSelHeadertxt, x, y, &x1, &y1, &w, &h);
      printThis( 0, 110, pcurSelHeadertxt, CENTER_ALIGNMENT);
    }


  display.updateWindow(0, 0,  250,  128, true);

}


#define STR_SEARCHING "Searching"

void renderSearching() {
  char temp_str[16];
  int16_t w;

  display.fillScreen(GxEPD_WHITE);
  display.drawRoundRect(0, 6, 250, 122, 10, GxEPD_BLACK);
  display.drawFastHLine(0, 76, 250, GxEPD_BLACK);
  display.drawBitmap(bitmap_FX, 30, 19,  200, 45, GxEPD_BLACK);

  strcpy(temp_str,STR_SEARCHING);
  for(uint8_t i = 0; i < searching_ctr; i++) {
    strcat(temp_str,".");
  }

  display.setFont(&FreeSansBold18pt7b);
  printThis( 0, 112, temp_str, CENTER_ALIGNMENT);


  //renderDeviceVBatt();
  searching_ctr++;
  searching_ctr %= 4;

  display.updateWindow(0, 0,  250,  128, true);
 
}

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
 /**
   * Called for each advertising BLE server.
   */
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    // We have found a device, let us now see if it contains the service we are looking for.
    if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(deviceUUID)) {
      BLEDevice::getScan()->stop();
      myDevice = new BLEAdvertisedDevice(advertisedDevice);
      state = STATE_CONNECTING;
    } // Found our server
  } // onResult
}; // MyAdvertisedDeviceCallbacks

void do_scan() {
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setInterval(1349);
  pBLEScan->setWindow(449);
  pBLEScan->setActiveScan(true);
  pBLEScan->start(1, false);
}

bool writeChar(BLERemoteService* pRemoteService, int idx, uint8_t value)
{
  // Obtain a reference to the characteristic in the service of the remote BLE server.
  pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUIDs[idx]);
  if (pRemoteCharacteristic == nullptr) {
    return false;
  }

  // Read the value of the characteristic.
  if(pRemoteCharacteristic->canWrite()) {
    pRemoteCharacteristic->writeValue(&value, 1);
  }
  return true;
}

bool readChar(BLERemoteService* pRemoteService, int idx, uint8_t * value)
{
  // Obtain a reference to the characteristic in the service of the remote BLE server.
  pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUIDs[idx]);
  if (pRemoteCharacteristic == nullptr) {
    return false;
  }

  // Read the value of the characteristic.
  if(pRemoteCharacteristic->canRead()) {
    std::string v = pRemoteCharacteristic->readValue();
    *value = v[0];
  }
  return true;
}

/* 
 4.5V = 100%
 3.6V = 0%

  50-100% Green     > 4.05V
  25-50% Yellow   
  0-25% Red       < 3.85V
 */ 
void renderChronyVBatt(){
  uint8_t vb;

  char temp_str[16];

  //sprintf (temp_str, "%.1fV", chronyVBattery);
  sprintf (temp_str, "%.1f", chronyVBattery);
  display.setFont(&FreeSansBold9pt7b);
  printThis( 212, 120, temp_str, LEFT_ALIGNMENT);
}

//void renderDeviceVBatt() {

//   char temp_str[16];
//   uint32_t vbat = esp_adc_cal_raw_to_voltage(analogRead(34), &adc_chars);
//   float fbat = ((float)vbat / 4095.0) * 2.0 * 3.3 * (1100 / 1000.0);


//   sprintf (temp_str, "D %.1fV", fbat);
//   display.setFont(&FreeMonoBold9pt7b);
//   printThis( 0, 20, temp_str, CENTER_ALIGNMENT);
//}

bool readBattery(){
  uint8_t vb;
  if(!readChar(pRemoteService, 3, &vb)) {
    return false;
  }
  chronyVBattery = (vb * 20.0)/1000;
  return true;  
}

#define MAX_SHOT_HISTORY 4

static void notifyCallback(

  BLERemoteCharacteristic* pBLERemoteCharacteristic,
  uint8_t* pData,
  size_t length,
  bool isNotify) {
  char sbuffer[256];
  // Third byte is return in steps of 5%, anything better than 10% we display  
  uint8_t r = ((char*)pData)[2] * 5;
  uint8_t pellet_index = get_pellet_index(gun_index);
  uint16_t speed;
  shot_stats_t ss;
  uint8_t start_at, end_at, i;
  int idx;

  if((r >= sensitivity) && !renderMenu) {
    display_on_at = seconds();
    power_saving = false;

    renderMenu = false;

    speed = ((char*)pData)[0];
    speed <<= 8;
    speed |= ((char*)pData)[1];

    float energy;
    float fspeed = speed;

    display.fillScreen(GxEPD_WHITE);
    display.drawRoundRect(0, 6, 250, 122, 10, GxEPD_BLACK);
    display.drawFastVLine(210, 0, 128, GxEPD_BLACK);
    display.drawFastHLine(0, 25, 250, GxEPD_BLACK);
    display.drawFastVLine(130, 45, 128, GxEPD_BLACK);
    display.drawFastHLine(0, 45, 250, GxEPD_BLACK);
    display.drawFastHLine(210, 100, 250, GxEPD_BLACK);

    display.setFont(&FreeSans9pt7b);
    display.setCursor(5, 22);
    display.print("Gun:");
    display.setCursor(5, 42);
    display.print("Pellet:");
    display.setCursor(215, 23);
    display.print("R%");
    display.setCursor( 238, 120);
    display.print("v");
    display.setCursor( 225, 60);
    display.print("#");
    display.setCursor(50, 60);
    if(units == UNITS_IMPERIAL) {
        display.print("FPS");
      } else {
        display.print("m/s");
      } 
      if(units == UNITS_IMPERIAL) {
        display.setCursor(93, 123); 
        display.print("FPE");
      } else {
        display.setCursor(102, 123); 
        display.print("J");
      }

    display.setFont(&FreeSansBold24pt7b);
    if(units == UNITS_IMPERIAL) {
      fspeed *= 0.0475111859;
      sprintf (sbuffer, "%d", int(fspeed));
      printThis( -115, 100, sbuffer, CENTER_ALIGNMENT); // Speed FPS
    } else {
      fspeed *= 0.014481409;
      sprintf (sbuffer, "%d", int(fspeed));
      printThis( -95, 100, sbuffer, CENTER_ALIGNMENT); // Speed m/s
    }



    /* Draw the Pellet energy */
    display.setFont(&FreeSans12pt7b);    
    if(units == UNITS_IMPERIAL) {
      energy = (my_pellets[pellet_index].pellet_weight_grains * powf(fspeed, 2))/450240;
      sprintf (sbuffer, "%.2f", energy);
      printThis( -115, 124, sbuffer, CENTER_ALIGNMENT); // Joules FPE
    } else {
      energy = 0.5 * (my_pellets[pellet_index].pellet_weight_grams / 1000) * powf(fspeed, 2);
      sprintf (sbuffer, "%.2f", energy);
      printThis( -105, 124, sbuffer, CENTER_ALIGNMENT); // Joules      
    }

    display.setFont(&FreeSansBold9pt7b);
    sprintf(sbuffer, "%s ", my_guns[gun_index].gun_name);
    printThis( 55, 22, sbuffer, LEFT_ALIGNMENT); // Gun

    sprintf(sbuffer, "%s", my_pellets[pellet_index].pellet_name);
    printThis( 55, 42, sbuffer, LEFT_ALIGNMENT); // Pellet

    add_shot(gun_index, fspeed);

    shotStringStats(&ss);


    //display.setFont(&FreeSansBold9pt7b);
    display.setFont(&FreeSans9pt7b);    // No bold for Min, Max,Av
    sprintf(sbuffer, "Mx %d", (int)ss.max);  
    printThis( 90, 62, sbuffer, CENTER_ALIGNMENT); // MAx
    sprintf(sbuffer, "Mn %d", (int)ss.min);
    printThis( 90, 77, sbuffer, CENTER_ALIGNMENT);  // Min
    sprintf(sbuffer, "Av %d", (int)ss.avg);
    printThis( 90, 92, sbuffer, CENTER_ALIGNMENT); // Average
    display.setFont(&FreeSansBold9pt7b);   // Bold for ES, SD only
    sprintf(sbuffer, "ES %.1f", ss.es);
    printThis( 90, 107, sbuffer, CENTER_ALIGNMENT); // ES
    sprintf(sbuffer, "SD %.1f", ss.sd);
    printThis( 90, 122, sbuffer, CENTER_ALIGNMENT);  // SD




    display.setFont(&FreeSansBold18pt7b);
    sprintf (sbuffer, "%d", get_string_length(gun_index), my_guns[gun_index].shot_string_length);
    printThis( 207, 93, sbuffer, CENTER_ALIGNMENT); // Shot#

    display.setFont(&FreeSansBold9pt7b);
    sprintf (sbuffer, "%d%", r);
    printThis( 207, 41, sbuffer, CENTER_ALIGNMENT); // R%
















    //renderDeviceVBatt();
    renderChronyVBatt();

    display.updateWindow(0, 0,  250,  128, true);//*******************************************************************************
  }
  nc_counter++;
  nc_counter %= 5;

}

uint8_t profile_bytes[2][5] = {{0x32, 0x32, 0x32, 0x32, 0x64},{0x17, 0x1E, 0x2D, 0x43, 0x5A}};

void connectToChrony() {

  char temp_str[16];

  display.fillScreen(GxEPD_WHITE);
  display.drawRoundRect(0, 6, 250, 122, 10, GxEPD_BLACK);
  display.drawFastHLine(0, 76, 250, GxEPD_BLACK);
  display.drawBitmap(bitmap_FX, 30, 19,  200, 45, GxEPD_BLACK);
  display.setFont(&FreeSansBold18pt7b);
  printThis( 0, 112, "Waiting Shot", CENTER_ALIGNMENT);
  display.updateWindow(0, 0,  250,  128, true);


  pClient  = BLEDevice::createClient();
  pClient->setClientCallbacks(new MyClientCallback());
  // Connect to the remove BLE Server.
  pClient->connect(myDevice);

  // Obtain a reference to the service we are after in the remote BLE server.
  pRemoteService = pClient->getService(serviceUUID);
  if (pRemoteService == nullptr) {
    pClient->disconnect();
    dirty = true;
    state = STATE_IDLE;
    return;
  }

  if(!writeChar(pRemoteService, 2, profile_bytes[0][my_guns[gun_index].gun_profile]))
  {
    pClient->disconnect();
    dirty = true;
    state = STATE_IDLE;
    return;
  }
  if(!writeChar(pRemoteService, 4, profile_bytes[1][my_guns[gun_index].gun_profile]))
  {
    pClient->disconnect();
    dirty = true;
    state = STATE_IDLE;
    return;
  }
  
  pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUIDs[0]);
  if (pRemoteCharacteristic == nullptr) {
    pClient->disconnect();
    dirty = true;
    state = STATE_IDLE;
    return;
  }

  if(pRemoteCharacteristic->canNotify()) {
    pRemoteCharacteristic->registerForNotify(notifyCallback);
  } else {
    pClient->disconnect();
    dirty = true;
    state = STATE_IDLE;
    return;      
  }

  readBattery();

  state = STATE_CONNECTED;    
  //tft.fillScreen(TFT_BLACK); 
  power_saving = true;
}

void loop() {
  unsigned long now = seconds();  

  if( !power_saving && 
      !renderMenu && 
      state != STATE_IDLE && 
      (power_save_duration != 0) &&
      (display_on_at + power_save_duration) < now) 
  {
    display_on_at = seconds();
    power_saving = true;
  }


  button.tick();
  if(dirty) {
    if(power_saving) {
      display_on_at = seconds();
      //u8g2.setPowerSave(0);
      power_saving = false;
    }
    if(renderMenu){
      doRenderMenu();
    }
    dirty = false;
  }

  switch(state)
  {
    case STATE_IDLE:
//      if(!dirty) { 
        renderSearching();
        do_scan(); 
//      }
      break;
    case STATE_OFFLINE:
      break;
    case STATE_CONNECTING:
      connectToChrony();
      break;
    case STATE_CONNECTED:
      if(now - chronyVBattLastRead > 5) {
        readBattery();
        chronyVBattLastRead = now;
      }        
      break;
  }
}


/* 
  Menu system
*/


static void sleepCallback(uint8_t param)
{
  //u8g2.setPowerSave(1);
  esp_deep_sleep_start();
}

static menuItem_t menu_sleep[] = {
  { "Zzzz",  NULL, menu_sleep, NULL, NULL, sleepCallback, 0, NULL},
};

void menuItemGenStringCurSleep(uint8_t, char * buffer)
{
  sprintf(buffer, "[%s]", menu_sleep[0].menuString);
}

static const uint8_t power_save_duration_lut[] = {0,2,5,10,20,40,60};

static void powerSaveCallback(uint8_t param)
{
  if(power_save_duration != power_save_duration_lut[param]) {
    power_save_duration = power_save_duration_lut[param];
    EEPROM.write(4, power_save_duration);
    EEPROM.commit();
  }  
  pCurrentMenuItem = menuStack[--menuStackIndex];
}

static menuItem_t menu_power_save[] = {
  { "Off",  NULL, &menu_power_save[1], NULL, NULL, powerSaveCallback, 0, NULL},
  { "2s",   NULL, &menu_power_save[2], NULL, NULL, powerSaveCallback, 1, NULL},
  { "5s",   NULL, &menu_power_save[3], NULL, NULL, powerSaveCallback, 2, NULL},
  { "10s",  NULL, &menu_power_save[4], NULL, NULL, powerSaveCallback, 3, NULL},
  { "20s",  NULL, &menu_power_save[5], NULL, NULL, powerSaveCallback, 4, NULL},
  { "40s",  NULL, &menu_power_save[6], NULL, NULL, powerSaveCallback, 5, NULL},
  { "60s",  NULL, &menu_power_save[0], NULL, NULL, powerSaveCallback, 6, NULL},
};

void menuItemGenStringCurPowerSaving(uint8_t, char * buffer)
{
  uint8_t idx = 0;
  switch(power_save_duration)
  {
    case 2:  idx = 1;  break;
    case 5:  idx = 2;  break;
    case 10: idx = 3;  break;
    case 20: idx = 4;  break;
    case 40: idx = 5;  break;
    case 60: idx = 6;  break;
  }  
  sprintf(buffer, "[%s]", menu_power_save[idx].menuString);
}

static void displayFlipCallback(uint8_t param)
{
  display_flip = param;
  EEPROM.write(3, display_flip);
  EEPROM.commit();
  display.setRotation(display_flip ? 1 : 3);
  pCurrentMenuItem = menuStack[--menuStackIndex];
}

static menuItem_t menu_display_flip[] = {
  { "Off",         NULL, &menu_display_flip[1], NULL, NULL, displayFlipCallback, DISPLAY_FLIP_OFF, NULL},
  { "On",          NULL, &menu_display_flip[0], NULL, NULL, displayFlipCallback, DISPLAY_FLIP_ON, NULL}
};

void menuItemGenStringCurDisplayFlip(uint8_t, char * buffer)
{
  sprintf(buffer, "[%s]", menu_display_flip[display_flip].menuString);
}

static void unitsCallback(uint8_t param)
{
  units = param;
  EEPROM.write(1, units);
  EEPROM.commit();
  pCurrentMenuItem = menuStack[--menuStackIndex];
}

static menuItem_t menu_units[] = {
  { "FPS",          NULL, &menu_units[1], NULL, NULL, unitsCallback, UNITS_IMPERIAL, NULL},
  { "M/S",          NULL, &menu_units[0], NULL, NULL, unitsCallback, UNITS_METRIC, NULL}
};

void menuItemGenStringCurSelUnits(uint8_t, char * buffer)
{
  sprintf(buffer, "[%s]", menu_units[units].menuString);
}

static void sensitivityIncCallback(uint8_t param)
{
  if(sensitivity <= 95){ 
    sensitivity += 5;
    EEPROM.write(0, sensitivity);
    EEPROM.commit();
  }
}
static void sensitivityDecCallback(uint8_t param)
{ 
  if(sensitivity >= 5){
    sensitivity -= 5;
    EEPROM.write(0, sensitivity);
    EEPROM.commit();
  }
}

static menuItem_t menu_sensitivity[] = {
  { "Increase",     NULL, &menu_sensitivity[1], NULL, NULL, sensitivityIncCallback, 0, NULL},
  { "Decrease",     NULL, &menu_sensitivity[0], NULL, NULL, sensitivityDecCallback, 0, NULL}
};

void menuItemGenStringSensitivity(uint8_t, char * buffer)
{
  sprintf(buffer, "%d %%", sensitivity);
}

void menuItemGenStringCurSelSensitivity(uint8_t, char * buffer)
{
  sprintf(buffer, "[%d %%]", sensitivity);
}

static void selectPelletCallback(uint8_t param)
{
  set_pellet_index(gun_index, param);
  pCurrentMenuItem = menuStack[--menuStackIndex];
}

void menuItemGenStringPellet(uint8_t i, char * buffer)
{
  if(units == UNITS_IMPERIAL) {
    sprintf(buffer, "%s %.3f %.3f", my_pellets[i].pellet_mfr, my_pellets[i].pellet_weight_grains, my_pellets[i].pellet_caliber_inch);
  } else {
    sprintf(buffer, "%s %.3f %.3f", my_pellets[i].pellet_mfr, my_pellets[i].pellet_weight_grams, my_pellets[i].pellet_caliber_mm);
  }
}

void menuItemGenStringCurSelPellet(uint8_t i, char * buffer)
{
  uint8_t pellet_index = get_pellet_index(gun_index);
  sprintf(buffer, "[%s]",my_pellets[pellet_index].pellet_name);
}

static void selectGunCallback(uint8_t param)
{
  gun_index = param;
  EEPROM.write(2, gun_index);
  EEPROM.commit();
  pCurrentMenuItem = menuStack[--menuStackIndex];
  build_pellet_menu();
  profile_changed = true;
}

void menuItemGenStringGun(uint8_t i, char * buffer)
{
  if(units == UNITS_IMPERIAL) {
    sprintf(buffer, "%s %.3f", my_guns[i].gun_mfr, my_guns[i].gun_caliber_inch);
  } else {
    sprintf(buffer, "%s %.3f", my_guns[i].gun_mfr, my_guns[i].gun_caliber_mm);
  }
}

void menuItemGenStringCurSelGun(uint8_t i, char * buffer)
{
  sprintf(buffer, "[%s]",my_guns[gun_index].gun_name);
}

void shotStringStats(shot_stats_t * ss)
{
  float speed, dist, sum = 0, sum_of_dists_sqd = 0;
  uint8_t i, scnt = get_string_length(gun_index);
  if(scnt == 0) {
    ss->min = 0;
    ss->max = 0;
    ss->avg = 0;
    ss->es = 0;
    ss->sd = 0;
    return;    
  }

  ss->min = 1000000;
  ss->max = 0;

  for(i = 0; i < scnt; i++) {
    speed = get_shot(gun_index, i);
    if(speed < ss->min){
      ss->min = speed;
    }
    if(speed > ss->max){
      ss->max = speed;
    }
    sum += speed;
  }

  ss->avg = sum / (float)scnt;
  ss->es = ss->max - ss->min;

  for(i = 0; i < scnt; i++) {
    speed = get_shot(gun_index, i);
    if(speed > ss->avg) {
      dist = (speed - ss->avg);
    } else {
      dist = (ss->avg - speed);
    }
    sum_of_dists_sqd += powf(dist, 2);
  }
  ss->sd = sqrtf(sum_of_dists_sqd / (float)scnt);
}

static void shotStringClearCallback(uint8_t param)
{
  clear_string(gun_index);
}

static void shotStringDumpCallback(uint8_t param)
{
  shot_stats_t stats;
  uint8_t pellet_index = get_pellet_index(gun_index);
  uint8_t i, scnt = get_string_length(gun_index);
  Serial.printf("Shot String\n");
  Serial.printf("Gun %s %s\n",my_guns[gun_index].gun_mfr, my_guns[gun_index].gun_name);
  if(units == UNITS_IMPERIAL) {
    Serial.printf("Ammo %s %.3f %.3f\n",my_pellets[pellet_index].pellet_name, my_pellets[pellet_index].pellet_caliber_inch, my_pellets[pellet_index].pellet_weight_grains);
  } else {
    Serial.printf("Ammo %s %.3f %.3f\n",my_pellets[pellet_index].pellet_name, my_pellets[pellet_index].pellet_caliber_mm, my_pellets[pellet_index].pellet_weight_grams);
  }

  shotStringStats(&stats);  
  Serial.printf("Minimum : %.2f\n",stats.min);
  Serial.printf("Maximum : %.2f\n",stats.max);
  Serial.printf("Average : %.2f\n",stats.avg);
  Serial.printf("ES      : %.2f\n",stats.es);
  Serial.printf("SD      : %.2f\n",stats.sd);

  for(i = 0; i < scnt; i++) {
    Serial.printf("Shot %d: %.2f\n", i+1, get_shot(gun_index, i));
  }
}

static void shotStringInitCallback(uint8_t param)
{
  uint8_t i;
  for(i = 0; i < NUM_GUNS; i++) {
    clear_string(i);
  }
  pCurrentMenuItem = menuStack[--menuStackIndex];
}

static void shotStringStatsCallback(uint8_t param)
{
  int16_t x = 0;
  int16_t y = 0;
  int16_t x1, y1;
  uint16_t w, h;

  shot_stats_t stats;
  char sbuffer[128];
  shotStringStats(&stats);  

  display.fillScreen(GxEPD_WHITE);
  display.drawRoundRect(0, 6, 250, 122, 10, GxEPD_BLACK);
  display.setFont(&FreeSansBold12pt7b);

  sprintf(sbuffer, "Min : %d\n",(int)stats.min);
  printThis( 0, 30, sbuffer, CENTER_ALIGNMENT);

  sprintf(sbuffer, "Max : %d\n",(int)stats.max);
  printThis( 0, 53, sbuffer, CENTER_ALIGNMENT);

  sprintf(sbuffer, "Ave : %d\n",(int)stats.avg);
  printThis( 0, 78, sbuffer, CENTER_ALIGNMENT);

  sprintf(sbuffer, "ES  : %.2f\n",stats.es);
  printThis( 0, 99, sbuffer, CENTER_ALIGNMENT);

  sprintf(sbuffer, "SD  : %.2f\n",stats.sd);
  printThis( 0, 122, sbuffer, CENTER_ALIGNMENT);


  display.updateWindow(0, 0,  250,  128, true);


  sleep(5);
}


static uint8_t review_counter;

void menuItemGenStringShotStringReview(uint8_t, char * buffer)
{
  if(get_string_length(gun_index) == 0){
    sprintf(buffer, "0/0: ---");
  } else {
    sprintf(buffer, "%d/%d: %d", review_counter + 1, get_string_length(gun_index), (int)get_shot(gun_index, review_counter));
    review_counter++;
    if(review_counter >= get_string_length(gun_index)){
      review_counter = 0;
    }
  }
}

void menuItemGenStringCurSelReview(uint8_t, char * buffer)
{
  sprintf(buffer, "");
  review_counter = 0; 
}

void shotStringReviewCallback(uint8_t)
{

}

static menuItem_t menu_shot_string_review[] = {
  { "Next",       NULL, &menu_shot_string_review[0], NULL, NULL, shotStringReviewCallback, 0, NULL},
};

static menuItem_t menu_shot_string[] = {
  { "Stats",       NULL, &menu_shot_string[1], NULL, NULL, shotStringStatsCallback, 0, NULL},
  { "Review",      menuItemGenStringShotStringReview, &menu_shot_string[2], menu_shot_string_review, menu_shot_string_review, NULL, 0, menuItemGenStringCurSelReview},
  { "Dump",        NULL, &menu_shot_string[3], NULL, NULL, shotStringDumpCallback, 0, NULL},
  { "Clear",       NULL, &menu_shot_string[4], NULL, NULL, shotStringClearCallback, 0, NULL},
  { "Initialise",  NULL, &menu_shot_string[0], NULL, NULL, shotStringInitCallback, 0, NULL}
};

void menuItemGenStringCurShotString(uint8_t, char * buffer)
{
  sprintf(buffer, "[%d]", get_string_length(gun_index));
}


static menuItem_t menu_top_level[] = {
  { "Gun",          NULL, &menu_top_level[1], NULL,             NULL,             NULL, 0, menuItemGenStringCurSelGun},
  { "Pellet",       NULL, &menu_top_level[2], NULL,             NULL,             NULL, 0, menuItemGenStringCurSelPellet},
  { "Shot String",  NULL, &menu_top_level[3], menu_shot_string, menu_shot_string, NULL, 0, menuItemGenStringCurShotString},
  { "Min. Return", menuItemGenStringSensitivity, &menu_top_level[4], menu_sensitivity, menu_sensitivity, NULL, 0, menuItemGenStringCurSelSensitivity},
  { "Units",        NULL, &menu_top_level[5], menu_units,       menu_units,       NULL, 0, menuItemGenStringCurSelUnits},
  { "Display Flip", NULL, &menu_top_level[6], menu_display_flip,menu_display_flip,NULL, 0, menuItemGenStringCurDisplayFlip},
  { "Power Save",   NULL, &menu_top_level[7], menu_power_save, menu_power_save,  NULL, 0, menuItemGenStringCurPowerSaving},
  { "Sleep",        NULL, &menu_top_level[0], menu_sleep,      menu_sleep,        NULL, 0, menuItemGenStringCurSleep}
  
};

bool is_pellet_for_gun(uint8_t pidx)
{
  bool result = false;

  if (units == UNITS_IMPERIAL) {
    result = ((my_pellets[pidx].pellet_caliber_inch != 0) && (my_guns[gun_index].gun_caliber_inch != 0)) && (my_pellets[pidx].pellet_caliber_inch == my_guns[gun_index].gun_caliber_inch);    
  } else {
    result = ((my_pellets[pidx].pellet_caliber_mm != 0) && (my_guns[gun_index].gun_caliber_mm != 0)) && (my_pellets[pidx].pellet_caliber_mm == my_guns[gun_index].gun_caliber_mm);
  }
  return result;
}

uint8_t num_pellets_for_gun()
{
  uint8_t i, pcnt = 0;
  for(i=0;i<NUM_PELLETS;i++) {
    if(is_pellet_for_gun(i)) {
      pcnt += 1;
    }
  }
  return pcnt;
}

void build_pellet_menu()
{
  bool found_pellet;
  uint8_t pellet_index, i, npellets, nctr = 0;
  if(menu_pellet) {
    free(menu_pellet);
  }
  npellets = num_pellets_for_gun();

  menu_pellet = (menuItem_t *)malloc(npellets * sizeof(menuItem_t));

  for(i=0;i<NUM_PELLETS;i++) {
    if(is_pellet_for_gun(i)) {
      menu_pellet[nctr].menuString = my_pellets[i].pellet_name;
      menu_pellet[nctr].menuItemGenString = NULL;
      menu_pellet[nctr].nextMenuItem = ((nctr == npellets - 1) ? &menu_pellet[0] : &menu_pellet[nctr+1]);
      menu_pellet[nctr].currentSubMenu = NULL;
      menu_pellet[nctr].subMenu = NULL;
      menu_pellet[nctr].menuItemCallback = selectPelletCallback;
      menu_pellet[nctr].param = i;
      menu_pellet[nctr].menuItemGenCurSelString = menuItemGenStringPellet;
      nctr += 1;
    }
  }

  menu_top_level[1].currentSubMenu = menu_pellet;
  menu_top_level[1].subMenu = menu_pellet;
  found_pellet = false;  
  pellet_index = get_pellet_index(gun_index);
 
  for(i = 0; i < nctr; i++) {
    if(pellet_index == menu_pellet[i].param) {
      found_pellet = true;
      break;
    }
  }
  if(!found_pellet) {
    set_pellet_index(gun_index, menu_pellet[0].param);
  }
}

//Name, Manufacturer, caliber in inches, caliber in mm, profile (speed range)
void build_gun_menu()
{
  uint8_t i;
  menu_gun = (menuItem_t *)malloc(NUM_GUNS * sizeof(menuItem_t));
  for(i=0;i<NUM_GUNS;i++) {
    menu_gun[i].menuString = my_guns[i].gun_name;
    menu_gun[i].menuItemGenString = NULL;
    menu_gun[i].nextMenuItem = ((i == NUM_GUNS - 1) ? &menu_gun[0] : &menu_gun[i+1]);
    menu_gun[i].currentSubMenu = NULL;
    menu_gun[i].subMenu = NULL;
    menu_gun[i].menuItemCallback = selectGunCallback;
    menu_gun[i].param = i;
    menu_gun[i].menuItemGenCurSelString = menuItemGenStringGun;
  }
  menu_top_level[0].currentSubMenu = menu_gun;
  menu_top_level[0].subMenu = menu_gun;
  build_pellet_menu();
}

static menuItem_t menu_entry = {  "Settings", NULL, menu_top_level, menu_top_level, NULL, NULL, 0, NULL };

void singleClick()
{
  if(renderMenu)
  {
    dirty = true;
    pCurrentMenuItem->currentSubMenu = pCurrentMenuItem->currentSubMenu->nextMenuItem;
  } else {
    if(power_saving) {
      display_on_at = seconds();
      //u8g2.setPowerSave(0);
      power_saving = false;
    }
  }
}

void doubleClick()
{
  if(renderMenu)
  {
    dirty = true;

    if(pCurrentMenuItem->currentSubMenu->menuItemCallback != NULL)
    {
      (*pCurrentMenuItem->currentSubMenu->menuItemCallback)(pCurrentMenuItem->currentSubMenu->param);
    } else {
      if(pCurrentMenuItem->currentSubMenu != NULL) {
        menuStack[menuStackIndex++] = pCurrentMenuItem;
        pCurrentMenuItem = pCurrentMenuItem->currentSubMenu;
      }
    }
  }
}

void longPressStop()
{
  if(renderMenu) {
    if(menuStackIndex == 1) {
      renderMenu = false;
      //tft.fillScreen(TFT_BLACK);
      display.fillScreen(GxEPD_WHITE);
      display.drawRoundRect(0, 6, 250, 122, 10, GxEPD_BLACK);
      display.drawFastHLine(0, 76, 250, GxEPD_BLACK);
      display.drawBitmap(bitmap_FX, 30, 19,  200, 45, GxEPD_BLACK);
      display.setFont(&FreeSansBold18pt7b);
      if(state == STATE_OFFLINE) {
        printThis( 0, 112, "OFFLINE", CENTER_ALIGNMENT);
      } else {
        printThis( 0, 112, "Waiting Shot", CENTER_ALIGNMENT);
      }
      display.updateWindow(0, 0,  250,  128, true);

      if(profile_changed) {
        ESP.restart();
        while(1){}
      }
      if(state == STATE_OFFLINE) {
        state = STATE_IDLE;
      }
    } else {
      dirty = true;
      pCurrentMenuItem = menuStack[--menuStackIndex];
    }
  } else if(state == STATE_CONNECTED) {
    profile_changed = false;
    dirty = true;
    renderMenu = true;
    pCurrentMenuItem = &menu_entry;
    menu_entry.currentSubMenu = menu_top_level;
    menuStackIndex = 0;
    menuStack[menuStackIndex++] = pCurrentMenuItem;
  } else if(state == STATE_IDLE) {
    state = STATE_OFFLINE;
    profile_changed = false;
    dirty = true;
    renderMenu = true;
    pCurrentMenuItem = &menu_entry;
    menu_entry.currentSubMenu = menu_top_level;
    menuStackIndex = 0;
    menuStack[menuStackIndex++] = pCurrentMenuItem;
  }
}


void printThis( uint16_t x, uint16_t y, const String &str, uint8_t alignment)
{
  //int16_t x;
  int16_t x1, y1;
  uint16_t w, h;
  //display.setCursor(x, y);
  display.getTextBounds(str, x, y, &x1, &y1, &w, &h);

  switch (alignment)
  {
  case RIGHT_ALIGNMENT:
    //display.setCursor( x + display.width() - w - x1, y);
    display.setCursor( x - w, y);
    break;
  case LEFT_ALIGNMENT:
    display.setCursor(x, y);
    break;
  case CENTER_ALIGNMENT:
    display.setCursor( x + 125 - ((w + x1) / 2), y);
    break;
  default:
    break;
  }
  display.print(str);
}

1 Like

Your code is already preformatted.

If you paste your code without code tags, that formatting gets destroyed, making the code difficult to read.

You saw the instructions. You followed them. It worked. As you can see, scrolling isn't a problem, even though there are 1250 code lines.

This seems to be a standard ESP32 function. Perhaps it has been replaced.

You mean these tabs circled? I just edited today morning the "gun.h".
Otherwise the code was working fine with couple similar edits in the past, before the arduino/libraries update today.

After I posted that, I realised that adc1_config_width() could be a standard ESP32 function, and a Google search confirmed that. So I deleted the post, but not before you had read it. Sorry!

Don't worry about my other tabs comment, it wasn't relevant.

The function that the error message is referring to does exist, it's mentioned here:

https://docs.espressif.com/projects/esp-idf/en/release-v3.3/api-reference/peripherals/adc.html#configuration-and-reading-adc

Do you have the correct board selected in the IDE? If you have a non-ESP32 board selected, that might explain why you get the error.

I was thinking about that, but...
the .ino file is called TTGO_v1.1_******
but I don't have that board on the list anymore, this what I am seeing only is the TTGO T7 v1.3 Mini32
and this after the libraries updated

... communicating with the board at com6

Is that what the code is asking or giving error?

Something to try
Open the board manager and install an earlier version of esp32 (2.0.15 for example)

I think you can find here the original software ( it has the same name ).
Installed libraries:

  • adafruit_gfx
  • GxEPD
  • OndeButton
  • OpenFontRender
    Arduino ide is 1.8.19 ( portable ), esp32 board manager v2.0.13, Selected board 'ESP32 dev module' ( not sure if this is the right module for your board ), it compiles without errors

That was the forum thread we were playing with boards.
I would need to find a arduino one ver earlier, I have my backup files from Jan/Feb 2023 I will replace.

That is the point of my hassle, my version of arduino ver 2.3.2 won't search for that esp32 board

It has nothing to do with the IDE, it's the esp32 boards.
do the following, click on 2.0.17

1 Like

Reverting the board driver worked, THANK YOU guys

Make sure you mark Solved on the post that gave you the answer so everyone knows.