Port selection greyed out immediately after sketch upload

Hey folks. I have been using Arduino for a few years. Relatively little experience about the inner workings of microcontrollers or the complexities of C++, but I have a sense my problem is with my sketch and library and not Arduino itself.

I am working on a project to create a simple state machine. It consists of three components: the state machine, states, and tasks. The state machine controls the states, states perform tasks at regular intervals, and tasks run functions.

I wrote a little custom library to do this since I figured I could use it in future projects. It consists of 3 header files and 1 implementation file.

task.h:

#ifndef task_h
#define task_h

class StateMachine;

class Task {
    public:
        float task_time = 0.0;
        float task_delta;
        void (*task_func)(StateMachine*);

        Task(void (*task_func)(StateMachine* state_machine), float task_delta);
        void perform(StateMachine* state_machine);
};

#endif

state.h:

#ifndef state_h
#define state_h

class Task;
class StateMachine;

class State {
    public:
        typedef Task* task_ptr;
        task_ptr tasks;
        typedef StateMachine* state_machine;

        State(StateMachine* state_machine);
        void update_state(StateMachine* state_machine);
};

#endif

state_machine.h:

#ifndef state_machine_h
#define state_machine_h

class State;

class StateMachine {
    public:
        typedef State* state_ptr;
        state_ptr states[10];
        int current_state;
        float run_time;

        StateMachine(float run_time, int start_state);
        void states_update();
};

#endif

venus.cpp:

#include "state.h"
#include "task.h"
#include "state_machine.h"

State::State(StateMachine* state_machine) {
    state_machine = state_machine;
}

void State::update_state(StateMachine* state_machine) {
    for (int i=0; i<2; i++) {
        if (state_machine->run_time-tasks->task_time >= tasks->task_delta) {
            tasks->perform(state_machine);
        }
    }
}

StateMachine::StateMachine(float run_time, int start_state) {
    current_state = start_state;
    run_time = run_time;
}

void StateMachine::states_update() {
    states[current_state]->update_state(this);
}

Task::Task(void (*task_func)(StateMachine* state_machine), float task_delta) {
    task_delta = task_delta;
    task_func = task_func;
}

void Task::perform(StateMachine* state_machine) {
    task_time = state_machine->run_time;
    this->task_func(state_machine);
}

Then I have a separate Arduino sketch that imports all three headers and I go ahead and actually define a task, state, and state machine. That can be seen here:

#include "state.h"
#include "task.h"
#include "state_machine.h"

StateMachine rocket(0.0, 1);



void sensor_read(StateMachine* state_machine) {
  Serial.println("nice");
}

Task read_sensors(&sensor_read, 1000.0);
State ground_idle(&rocket);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  ground_idle.tasks = &read_sensors;
  rocket.states[1] = &ground_idle;
}

void loop() {
  // put your main code here, to run repeatedly:
  rocket.run_time = millis();
  rocket.states_update();

}

If I include the this->task_func(state_machine); call in Task::perform in venus.cpp, then once the sketch is finished uploading, the Port option in the Tools dropdown immediately greys out and my Arduino can no longer connect to my computer. I get a usb device not recognized error on my computer. The error message that pops in the IDE after the Arduino disconnects can be seen here:

Arduino: 1.8.13 (Windows 10), Board: "Arduino Micro"

Sketch uses 4308 bytes (15%) of program storage space. Maximum is 28672 bytes.

Global variables use 195 bytes (7%) of dynamic memory, leaving 2365 bytes for local variables. Maximum is 2560 bytes.





processing.app.SerialException: Error opening serial port 'COM7'.

	at processing.app.Serial.<init>(Serial.java:152)

	at processing.app.Serial.<init>(Serial.java:82)

	at processing.app.SerialMonitor$2.<init>(SerialMonitor.java:132)

	at processing.app.SerialMonitor.open(SerialMonitor.java:132)

	at processing.app.AbstractMonitor.resume(AbstractMonitor.java:132)

	at processing.app.Editor.resumeOrCloseSerialMonitor(Editor.java:2120)

	at processing.app.Editor.access$1300(Editor.java:117)

	at processing.app.Editor$UploadHandler.run(Editor.java:2089)

	at java.lang.Thread.run(Thread.java:748)

Caused by: jssc.SerialPortException: Port name - COM7; Method name - openPort(); Exception type - Port not found.

	at jssc.SerialPort.openPort(SerialPort.java:167)

	at processing.app.Serial.<init>(Serial.java:141)

	... 8 more

Error opening serial port 'COM7'.



This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Once this has happened, in order to restore connection with the Arduino, I hold down the reset button. I upload any other sketch that doesn’t include that specific function call, and right as compile is complete, I release the reset button on the Arduino. The code is then able to upload and the Arduino stays connected.

This issue has occurred on both an Arduino Micro and a Teensy 4.0. Same exact symptoms. Neither board has caused any problems like this in the past.

So far I have tried:

  • commenting out the call (compiles, uploads, can still connect after)
  • putting a conditional in the code that always returns false and that conditional contains the rocket.states_update(); call (compiles, uploads, can still connect after)
  • reinstalling the Arduino IDE (issue persists)
  • uninstalling and reinstalling drivers (issue persists)

So, any ideas? It at least seems to be the actual execution of that function call, but that’s about as far as I can go with my current understanding of the issue. I’ll see if I can keep trying things tomorrow after work. I’m going crazy lol. I feel like this should work, but something just freaks out.

Let me know if you need more info, and a preemptive thank you to anyone willing to tackle this monster with me.

Both boards handle USB functionality on the main processor, so the symptom you see is probably caused by sketch running crazy. As your sketch uses function pointers I strongly guess it uses a null pointer somewhere and jumps into a non-existing location. As I don’t see what all methods intention was and there are no comments it’s up to you to find the exact reason.

A few things to look at:

    for (int i=0; i<2; i++) {
        if (state_machine->run_time-tasks->task_time >= tasks->task_delta) {
            tasks->perform(state_machine);
        }
    }

What’s the reason for the loop? The index variable isn’t used.

        typedef StateMachine* state_machine;

        State(StateMachine* state_machine);

I’m surprised, the compiler doesn’t complain. You define a type and use that types name afterwards as a variable name.

Using arrays without range checks is dangerous. Even more dangerous is not using the first element of the array but only the second one (but also there without checking the content). The code is quite a mess.

As your sketch uses function pointers I strongly guess it uses a null pointer somewhere and jumps into a non-existing location.

Using arrays without range checks is dangerous. Even more dangerous is not using the first element of the array but only the second one (but also there without checking the content). The code is quite a mess.

These were it. I wrote up a little sketch:

class Cool {
  public:
    typedef void (*task_func)(int cool);
    task_func funcs[10];
    int cool = 7;
    
    void perform() {
      for (int i=0;i<10;i++) {
        task_func func = funcs[i];
        func(this->cool);
      }
      
    }
};

Cool nice;

void fun(int cool) {
  Serial.println(cool);
}



void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  for (int i=0;i<10;i++){
    nice.funcs[i] = &fun;
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  nice.perform();
}

And messed around with the array indexing. If nice.funcs wasn’t fully populated with pointers, it would kill the Arduino.
Lessons learned:

  • Beware of null pointers putting you into a nonexistent memory location
  • Comment my code if I’m asking people to review it
  • Clean up my code if I’m asking people to review it
  • Make sure I’m not defining types with identical names as variables
  • Use range and content checks when using arrays

I appreciate the review and being able to point me in the right direction here, even if my code was messy. Frustration got the best of me there. I’ll see about either using something like the vector library or a config that defines the size of my arrays early on. You’re a real champ, pylon. Have a good one!

Aha, so doing some more troubleshooting, I found out exactly what was happening. It may have been a combination of null pointer errors, but the one that I couldn't see after fixing array sizes and indexing was in my Task constructor in venus.cpp:

Task::Task(void (*task_func)(StateMachine* state_machine), float task_delta) {
    task_delta = task_delta;
    task_func = task_func;
}

I was passing in task_func and assigning it to task_func. When I ran a sketch that printed out the address that my task_func pointer pointed to, it was zero. So I think something about passing in a variable with the same name as a class variable had it freak out.

I solved it by renaming the input variable or by prepending task_func such that:

this.task_func = task_func;

Cool, well that was interesting. Thanks again!