Get code structured using tabs...

Hi,
I wanted to get my code structured and separate into different tabs:

a_libraries and declarations
b_setup
c_runtime data processing
d_display
e_serial reporting
f_end loop
g_functions

My program that got compiled errorless, threw many errors after being split into tabs.
Even inside the function part the compiler complained that a function, that was defined in the same tab did not exist.

What are the limitations of the tabs-functionality, or is the just plain bugs?

If you want the normal Arduino IDE functionality, you should name your tabs "xxx.ino" rather than just "xxx"
Or you can do ".cpp" or ".c", but then you'll need to follow the C/C++ rules about using function prototypes.

one .ino must have the same name as the project folder. it should contain global variables because it is first in the final concatenation of ino files. the rest is concatenated in alphabet order

Juraj:
one .ino must have the same name as the project folder. it should contain global variables because it is first in the final concatenation of ino files. the rest is concatenated in alphabet order

OK the first tab with the same name as the project folder contains nothing to compile: only comments.
The rest is in alphabetic order, a_libraries and declarations contains the global variables.

Nevertheless it does not work. The compiler gets weird: it brings me an

exit status 1
expected ';' before ')' token

for a line of code that is in a large commented out block! :-/

P.S. I found the error elsewhere, but with tabbed code the compiler brings the wrong line numbers in its error reporting.
This appears to be a bug.

westfw:
If you want the normal Arduino IDE functionality, you should name your tabs "xxx.ino" rather than just "xxx"
Or you can do ".cpp" or ".c", but then you'll need to follow the C/C++ rules about using function prototypes.

I can't do that manually. The tabs already get the .ino extension automatically.

The tabs already get the .ino extension automatically.

But you can override the default extension or rename the tabs

Please put your entire sketch in a zip file and attach it to a reply in this thread. You will see the "Attachments and other options" link after you click the "Reply" button.

UKHeliBob:
But you can override the default extension or rename the tabs

No, if I try to rename the tab from "a_setup" to e.g. "a_setup.ino" I get an error that "a_setup.ino" already exists.

westfw:
If you want the normal Arduino IDE functionality, you should name your tabs "xxx.ino" rather than just "xxx"
Or you can do ".cpp" or ".c", but then you'll need to follow the C/C++ rules about using function prototypes.

Juraj:
one .ino must have the same name as the project folder. it should contain global variables because it is first in the final concatenation of ino files. the rest is concatenated in alphabet order

OK, I finally got it to compile.

I had to have all variables declared and all functions in the first tab.

RIN67630:
One need to have all variables declared and all functions in the first tab.

Not true.

RIN67630:
No, if I try to rename the tab from "a_setup" to e.g. "a_setup.ino" I get an error that "a_setup.ino" already exists.

Try this.
Create a new sketch and save it. Now look in the sketch folder. What files() are there ?
Add a new tab and name it a_setup. Do not give it a file extension.
Save the sketch. Now look in the sketch folder. What files() are there now ?

Now do you see why you cannot rename a_setup to a_setup.ino ? You could, however, rename it to a_setup.h or somethingelse.ino

If you don’t want to have all your functions in the first tab, you may be just need to declare function prototypes at the top of your code. I understand that it is good practice anyway.

the arduino build tool creates function prototypes for all functions from ino files and puts them at the beginning of the generated c++ source code. any function from any ino file of the project can be used in any ino file of the project. this doesn't apply to variables. variable defined outside of the function can be used in following functions in the concatenated ino. so the variable is visible in the following tabs

@Juraj, so the build tool gets it right nowadays? It used to fail miserably when using function pointers if the function was defined after using the function pointer (e.g. assign it to an element of an array of function pointers).

sterretje:
@Juraj, so the build tool gets it right nowadays? It used to fail miserably when using function pointers if the function was defined after using the function pointer (e.g. assign it to an element of an array of function pointers).

I use Eclipse IDE Arduino Sloeber plugin and it does it right. I have Arduino 1.8.5 IDE installed and it still has the problem with function pointers and Blynk macros

Thanks, saves me the time to test :slight_smile:

Personally I think that it allows for bad C/C++ programming habits. Or lazy programmers ( me included :frowning: ).

RIN67630:
Hi,
I wanted to get my code structured and separate into different tabs:

a_libraries and declarations
b_setup
c_runtime data processing
d_display
e_serial reporting
f_end loop
g_functions

My program that got compiled errorless, threw many errors after being split into tabs.
Even inside the function part the compiler complained that a function, that was defined in the same tab did not exist.

What are the limitations of the tabs-functionality, or is the just plain bugs?

Why do you want to do that? I've written a lot of rather complex programs and all I needed was the .INO file and a .H file.

It seems like splitting up your code into so many different files will do nothing but create a testing and debugging nightmare.

An important programming rule is K.I.S.S. which is "Keep It Simple Sir" (actually the second "S" stands for "Stupid", but I didn't want to insult). :slight_smile:

sterretje:
Personally I think that it allows for bad C/C++ programming habits. Or lazy programmers ( me included :frowning: ).

In my opinion it is ok for Arduino mcu projects. I decided to go the multiple ino code separation way with almost no encapsulation of partial functionality. I could make classes in cpp files with declarations in h files with public and private methods etc, but it is more work and I am lazy too :slight_smile:

krupski:
Why do you want to do that? I've written a lot of rather complex programs and all I needed was the .INO file and a .H file.

It seems like splitting up your code into so many different files will do nothing but create a testing and debugging nightmare.

An important programming rule is K.I.S.S. which is "Keep It Simple Sir" (actually the second "S" stands for "Stupid", but I didn't want to insult). :slight_smile:

it is simple if every xy.ino has xySetup() and xyLoop() and you call them from setup() and loop(). and then you can add some logic, timers and/or state machine to handle the flow of the loop().

#ifdef __IN_ECLIPSE__
//This is a automatic generated file
//Please do not modify this file
//If you touch this file your change will be overwritten during the next build
//This file has been generated on 2018-04-15 09:34:26

#include "Arduino.h"
#include <BlynkSimpleWiFiLink.h>
#include <BlynkWidgets.h>
#include <EEPROM.h>
#include <Grove_LED_Bar.h>
#include <MemoryFree.h>
#include <TimeLib.h>
#include <WiFiLink.h>
#include <UnoWiFiDevEdSerial1.h>
#include "consts.h"
#include "secrets.h"
#include <avr/wdt.h>

void balboaSetup() ;
void balboaReset() ;
void balboaLoop() ;
void beeperLoop() ;
void alarmSound() ;
void beep() ;
BLYNK_READ(GAUGE_WIDGET) ;
BLYNK_WRITE(MANUAL_RUN_BUTTON) ;
BLYNK_WRITE(VALVES_BACK_BUTTON) ;
void blynkSetup() ;
void blynkLoop() ;
void updateWidgets() ;
void buttonSetup() ;
void buttonLoop() ;
boolean elsensLoop() ;
boolean elsensCheckPump() ;
byte overheatedSecondsLeft() ;
int readElSens() ;
void eventsSetup() ;
void eventsLoop() ;
void eventsWrite(int newEvent, int value1, int value2) ;
boolean eventsSaved() ;
void eventsSave() ;
byte eventsRealCount() ;
void eventsPrint(Print& stream) ;
void eventsPrint(Print& s, int ix) ;
void eventsPrintJson(Print& stream) ;
void eventsPrintJson(Print& stream, int ix) ;
void ledBarSetup() ;
void ledBarLoop() ;
boolean manualRunLoop() ;
byte manualRunMinutesLeft() ;
void modbusSetup() ;
boolean modbusLoop() ;
void modbusClearData() ;
boolean requestSymoRTC() ;
boolean requestInverter() ;
boolean requestMeter() ;
boolean requestBattery() ;
boolean modbusError(int err) ;
int modbusRequest(byte uid, unsigned int addr, byte len, int *regs) ;
int timedRead(Stream &is, byte buffer[], size_t len) ;
void pilotLoop() ;
byte power2pwm(int power) ;
void setup() ;
void loop() ;
void handleSuspendAndOff() ;
boolean handleAlarm() ;
boolean restHours() ;
boolean turnMainRelayOn() ;
boolean wifiConnected() ;
void t2s(unsigned long t, char *buff) ;
void sprintfF(char* buf, const __FlashStringHelper *fmt, ... );
void restServerSetup() ;
void restServerLoop() ;
void printValuesJson(Print& client) ;
void printAlarmJson(Print& client) ;
void susCalibLoop() ;
void telnetSetup() ;
void telnetLoop(boolean log) ;
void valvesBackSetup() ;
void valvesBackReset() ;
void valvesBackLoop() ;
void valvesBackStart(int v) ;
boolean valvesBackExecuted() ;
void watchdogSetup() ;
void watchdogLoop() ;

#include "Regulator.ino"

#include "Balboa.ino"
#include "Beeper.ino"
#include "Blynk.ino"
#include "Button.ino"
#include "ElSens.ino"
#include "Events.ino"
#include "LedBar.ino"
#include "ManualRun.ino"
#include "Modbus.ino"
#include "PowerPilot.ino"
#include "RestServer.ino"
#include "SusCalib.ino"
#include "Telnet.ino"
#include "ValvesBack.ino"
#include "Watchdog.ino"

#endif
void loop() {

  loopStartMillis = millis();

  handleSuspendAndOff();

  watchdogLoop();
  eventsLoop();

  // user interface
  buttonPressed = false;
  buttonLoop();
  beeperLoop(); // alarm sound
  ledBarLoop();
  blynkLoop();
//  restServerLoop();
  telnetLoop(msg[0] != 0); // checks input commands and prints msg
  msg[0] = 0;  //clear msg

  if (handleAlarm())
    return;

  if (manualRunLoop())
    return;

  valvesBackLoop();

  if (restHours())
    return;

  if (!wifiConnected())
    return;

  susCalibLoop();

  if (modbusLoop()) { // returns true if data set is ready
    balboaLoop();

    if (elsensLoop()) { // evaluates OVERHEATED
      pilotLoop();
    }
    telnetLoop(true); // logs modbus and heating data
  }
}

GitHub repository of the project