Quite a bit of untested code but the only thing really concerning me at the moment is my DISPLAY variable. I don't see how it is much different than my FONT array (which works fine) yet DISPLAY is the one that gets 'invalid types 'int[int]' for array subscript' I should be able to index an array of integers with integers (at least I have been with FONT).
#include <WiFiNINA.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include "font.h"
const int PIXEL_WIDTH = 30;
const int PIXEL_HEIGHT = 5;
int DISPLAY[PIXEL_HEIGHT][PIXEL_WIDTH] = {};
bool MILI_TIME = false;
String FORMATTING[2] = {"LONGS","SHORTH:LONGM"};
char ssid[] = "REMOVED"; // your network SSID (name) between the " "
char pass[] = "REMOVED"; // your network password between the " "
int keyIndex = 0; // your network key Index number (needed only for WEP)
int status = WL_IDLE_STATUS; // connection status
WiFiServer server(80); // server socket
WiFiClient client = server.available();
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
int ledPin = LED_BUILTIN;
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
while (!Serial); // dont do anything until there is a serial connection
enable_WiFi();
connect_WiFi();
server.begin();
printWifiStatus();
timeClient.begin();
timeClient.setTimeOffset(-14400);
}
void loop() {
timeClient.update();
client = server.available();
if (client) {
printWEB();
}
preRender();
}
void preRender(){
String FILLED_FORMATTING[2] = FORMATTING;
for(int i=0;i<2;i++){
FILLED_FORMATTING[i].replace("LONGH",leadWithZero(timeHours()));
FILLED_FORMATTING[i].replace("LONGM",leadWithZero(timeMinutes()));
FILLED_FORMATTING[i].replace("LONGS",leadWithZero(timeSeconds()));
FILLED_FORMATTING[i].replace("SHORTH",timeHours());
FILLED_FORMATTING[i].replace("SHORTM",timeMinutes());
FILLED_FORMATTING[i].replace("SHORTS",timeSeconds());
}
int x = 0;
for(int i=0;i<FILLED_FORMATTING[0].length();i++){
int c_ID = charID(FILLED_FORMATTING[0][i]);
if(c_ID < 38){
for(int j=0;j<5;j++){
DISPLAY[j][x] = FONT[c_ID][j][0];
x += 1;
DISPLAY[j][x] = FONT[c_ID][j][1];
x += 1;
DISPLAY[j][x] = FONT[c_ID][j][2];
x += 1;
if(i != FILLED_FORMATTING[0].length()){
DISPLAY[j][x] = 0;
x += 1;
}
}
}
}
x = PIXEL_WIDTH-1;
for(int i=FILLED_FORMATTING[1].length()-1;i>=0;i--){
int c_ID = charID(FILLED_FORMATTING[1][i]);
if(c_ID < 38){
for(int j=0;j<5;j++){
DISPLAY[j][x] = FONT[c_ID][j][0];
x -= 1;
DISPLAY[j][x] = FONT[c_ID][j][1];
x -= 1;
DISPLAY[j][x] = FONT[c_ID][j][2];
x -= 1;
if(i != 0){
DISPLAY[j][x] = 0; //<----------- compiler error here, and ofc all instances above
x -= 1;
}
}
}
}
}
int charID(char c){
for(int i=0;i<FONT_ID.length();i++){
if(FONT_ID[i] == c){
return i;
}
}
return 40;
}
String timeHours(){
if(MILI_TIME){
return String(timeClient.getHours());
}
else{
return convFromMili(timeClient.getHours());
}
}
String timeMinutes(){
return String(timeClient.getMinutes());
}
String timeSeconds(){
return String(timeClient.getSeconds());
}
String leadWithZero(String t){
if(t.length() < 2){
t = "0"+t;
return t;
}
}
String convFromMili(int t){
if(t > 12){
t -= 12;
}else if(t == 0){
t += 12;
}
String ts = String(t);
return ts;
}
void printWifiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
Serial.print("To see this page in action, open a browser to http://");
Serial.println(ip);
}
void enable_WiFi() {
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true);
}
String fv = WiFi.firmwareVersion();
if (fv < "1.0.0") {
Serial.println("Please upgrade the firmware");
}
}
void connect_WiFi() {
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
status = WiFi.begin(ssid, pass);
delay(10000);
}
}
void printWEB() {
if (client) { // if you get a client,
Serial.println("new client"); // print a message out the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected()) { // loop while the client's connected
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println();
//create the buttons
client.print(WiFi.getTime());
client.print("<br>");
client.print(timeClient.getEpochTime());
client.print("<br>");
client.print(timeClient.getFormattedTime());
client.print("<br>");
client.print(timeClient.getDay());
client.print("<br>");
client.print(timeClient.getHours());
client.print("<br>");
client.print(timeClient.getMinutes());
client.print("<br>");
client.print(timeClient.getSeconds());
client.print("<br>");
client.print("<div style=\"display:block;padding-left:calc(50% - 150px);margin-bottom:50px\"><div style=\"background-color:#e3e3e3;width:300px;height:120px;font-size:50px;text-align:center;padding-top:50px\">ON</div></div>");
client.print("<div style=\"display:block;padding-left:calc(50% - 150px)\"><div style=\"background-color:#e3e3e3;width:300px;height:120px;font-size:50px;text-align:center;padding-top:50px\">OFF</div></div>");
// The HTTP response ends with another blank line:
client.println();
// break out of the while loop:
break;
}
else { // if you got a newline, then clear currentLine:
currentLine = "";
}
}
else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
if (currentLine.endsWith("GET /H")) {
digitalWrite(ledPin, HIGH);
}
if (currentLine.endsWith("GET /L")) {
digitalWrite(ledPin, LOW);
}
if (currentLine.endsWith("%VAL")) {
// Trim 'GET /' and '%VAL'
currentLine.remove(0,5);
currentLine.remove(currentLine.indexOf("%"),4);
Serial.println(currentLine);
Serial.println();
}
}
}
// close the connection:
client.stop();
Serial.println("client disconnected");
}
}
font.h:
int FONT[37][5][3] = {{{1,1,1},{1,0,1},{1,0,1},{1,0,1},{1,1,1},},{{1,1,0},{0,1,0},{0,1,0},{0,1,0},{1,1,1},},{{1,1,1},{0,0,1},{1,1,1},{1,0,0},{1,1,1},},{{1,1,1},{0,0,1},{1,1,1},{0,0,1},{1,1,1},},{{1,0,1},{1,0,1},{1,1,1},{0,0,1},{0,0,1},},{{1,1,1},{1,0,0},{1,1,1},{0,0,1},{1,1,1},},{{1,1,1},{1,0,0},{1,1,1},{1,0,1},{1,1,1},},{{1,1,1},{0,0,1},{0,0,1},{0,0,1},{0,0,1},},{{1,1,1},{1,0,1},{1,1,1},{1,0,1},{1,1,1},},{{1,1,1},{1,0,1},{1,1,1},{0,0,1},{1,1,1},},{{1,1,1},{1,0,1},{1,1,1},{1,0,1},{1,0,1},},{{1,1,0},{1,0,1},{1,1,0},{1,0,1},{1,1,0},},{{1,1,1},{1,0,0},{1,0,0},{1,0,0},{1,1,1},},{{1,1,0},{1,0,1},{1,0,1},{1,0,1},{1,1,0},},{{1,1,1},{1,0,0},{1,1,1},{1,0,0},{1,1,1},},{{1,1,1},{1,0,0},{1,1,1},{1,0,0},{1,0,0},},{{1,1,1},{1,0,0},{1,0,1},{1,0,1},{1,1,1},},{{1,0,1},{1,0,1},{1,1,1},{1,0,1},{1,0,1},},{{1,1,1},{0,1,0},{0,1,0},{0,1,0},{1,1,1},},{{0,0,1},{0,0,1},{0,0,1},{1,0,1},{1,1,1},},{{1,0,1},{1,0,1},{1,1,0},{1,0,1},{1,0,1},},{{1,0,0},{1,0,0},{1,0,0},{1,0,0},{1,1,1},},{{1,1,1},{1,1,1},{1,0,1},{1,0,1},{1,0,1},},{{1,1,0},{1,0,1},{1,0,1},{1,0,1},{1,0,1},},{{1,1,1},{1,0,1},{1,0,1},{1,0,1},{1,1,1},},{{1,1,1},{1,0,1},{1,1,1},{1,0,0},{1,0,0},},{{1,1,1},{1,0,1},{1,0,1},{1,1,0},{0,0,1},},{{1,1,1},{1,0,1},{1,1,0},{1,0,1},{1,0,1},},{{0,1,1},{1,0,0},{0,1,0},{0,0,1},{1,1,0},},{{1,1,1},{0,1,0},{0,1,0},{0,1,0},{0,1,0},},{{1,0,1},{1,0,1},{1,0,1},{1,0,1},{1,1,1},},{{1,0,1},{1,0,1},{1,0,1},{0,1,0},{0,1,0},},{{1,0,1},{1,0,1},{1,0,1},{1,1,1},{1,1,1},},{{1,0,1},{1,0,1},{0,1,0},{1,0,1},{1,0,1},},{{1,0,1},{1,0,1},{1,1,1},{0,0,1},{1,1,1},},{{1,1,1},{0,0,1},{0,1,0},{1,0,0},{1,1,1},},{{0,0,0},{0,1,0},{0,0,0},{0,1,0},{0,0,0}}};
String FONT_ID = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ:";
did check -
int D[5][30];
void setup() {
}
void loop() {
D[0][0] = 0;
}
and of course its fine, so I'm just wondering where I went wrong in the mess above?
and yes there's a good bit of mess/debugging stuff
Simple solution... don't use DISPLAY as a variable it seems. Changing to DISPLAY_ fixed it, figured the variable was defined as a normal integer somewhere... just not in my code.
I have an issue where my Arduino program hangs for no reason. I run my program, and at some undetermined point, the Serial Monitor stops printing output. Here's what I've tested so far:
In my "com.init_drone()" method, I've commented everything out except for the last line, which signals that the method returned. When I do this, my program hangs somewhere else but still it doesn't get to the infinite while loop.
I've been outputting memory usage, and I'm getting numbers no lower than 450 -- this tells me that I'm not using an absurd amount of memory.
I've tried removing the Timer1 instantiation, interrupt attach/detach, bu that has had no effect on the program.
My .ino file(and Command) is located here for anyone that wants a fuller picture and doesn't want to scroll through all this code I'm going to post below.
Here's my log output so far. Notice the truncation!:
AT&F
AT+NMAC=00:1d:c9:10:39:6f
AT+WM=0
AT+NDHCP=1
AT+WA=ardrone_279440
AT+NCUDP=192.168.1.1,5556
S0AT*CONFIG=1,"general:navdata_demo","TRUE"
EAT*CONFIG=1,"general:navdata_demo","TRUE"
638
S0AT*CONFIG=2,"control:altitude_max","2000"
EAT*CONFIG=2,"control:altitude_max","2000"
638
S0AT*CONFIG=3,"control:euler_angle_max","0.35"
EAT*CONFIG=3,"control:euler_angle_max","0.35"
586
S0AT*CONFIG=4,"control:outdoor","FALSE"
EAT*CONFIG=4,"control:outdoor","FALSE"
635
S0AT*CONFIG=5,"control:flight_without_shell","FALSE"
EAT*CONFIG=5,"control:flight_without_shell","FALSE"
574
S0AT*CTRL=6,4,0
EAT*CTRL=6,4,0
629
S0AT*CTRL=7,0,0
EAT*CTRL=7,0,0
629
S0AT*CTRL=8,4,0
EAT*CTRL=8,4,0
629
S0AT*COMWDG=9
EAT*COMWDG=9
629
S0AT*COMWDG=10
EAT*COMWDG=10
629
S0AT*COMWDG=11
EAT*COMWDG=11
629
S0AT*COMWDG=12
EAT*COMWDG=12
629
S0AT*COMWDG=13
EAT*COMWDG=13
629
S0AT*FTRIM=14
EAT*FTRIM=14
629
Here is my .ino file:
#include "Command.h"
#include "Streaming.h"
int debug = 1;
extern ring_buffer rx_buf;
extern resultint_ resultint;
Command com;
int sequenceNumber = 1;
String atcmd = "";
#include "TimerOne.h"
#define LEDpin 13
void setup()
{
PCsrl.begin(9600);
com.start_wifi_connection();
com.drone_is_init = com.init_drone();
Timer1.initialize(COMWDG_INTERVAL_USEC);
Timer1.attachInterrupt(watchdog_timer);
}
void watchdog_timer() {
com.sendwifi(com.makeComwdg());
}
void loop()
{
if (com.drone_is_init == 0) {
if (debug) {
// never use three ! together in arduino code
PCsrl.println("Drone wasn't initlized before loop() was called. Initalizing now.\r\n");
}
} else {
com.drone_takeoff();
com.drone_takeoff();
com.sendwifi(com.makePcmd(1,0,0,0,0));
com.sendwifi(com.makePcmd(1,0,0,0,0));
delay(5000);
com.moveForward(1);
com.moveRotate(180);
com.moveForward(1);
com.moveRotate(180);
delay(500);
com.drone_landing();
com.drone_landing();
delay(500);
//end of program
Timer1.detachInterrupt();
PCsrl.println("Program finished");
while (1){};
}
}
And my Command.cpp
#ifndef GAINSPAN
#define GAINSPAN
#include "Command.h"
extern int sequenceNumber;
extern int debug;
ring_buffer rx_buf= {{0}, 0, 0};
resultint_ resultint;
Command::Command()
{
at = "";
command = "";
s2ip_running = 0;
drone_is_init = 0;
drone_is_hover = 0;
emergency = 0;
}
void Command::sendwifi(String s) {
WIFIsrl.write(27); //esc
WIFIsrl.print("S0"); //choose connection CID 0
WIFIsrl.print(s);
WIFIsrl.write(27);
WIFIsrl.print("E");
if(debug) PCsrl.println(s);
WIFIsrl.println(memoryTest());
}
int Command::start_wifi_connection()
{
WIFIsrl.begin(9600);
WIFIsrl.println("");
WIFIsrl.println("AT&F");
//WIFIsrl.println("ATE0"); //turn off echo
WIFIsrl.print("AT+NMAC=00:1d:c9:10:39:6f\r"); //set MAC address
WIFIsrl.println("AT+WM=0");
WIFIsrl.println("AT+NDHCP=1");
/* drone's network profile, change if needed*/
WIFIsrl.println("AT+WA=ardrone_279440");
WIFIsrl.println("AT+NCUDP=192.168.1.1,5556");
readARsrl();
delay(3000); //need 3 seconds for connection to establish
return 0;
}
String Command::makeComwdg()
{
at = "AT*COMWDG=";
command = at + getSequenceNumber() + "\r\n";
return command;
}
void Command::sendComwdg_t(int msec)
{
for (int i = 0; i < msec; i+=20) {
sendwifi(makeComwdg());
delay(20);
}
}
void Command::sendFtrim()
{
at = "AT*FTRIM=";
command = at + getSequenceNumber() + "\r\n";
sendwifi(command);
}
void Command::sendConfig(String option, String value)
{
at = "AT*CONFIG=";
command = at + getSequenceNumber() + ",\"" + option + "\",\"" + value + "\"\r\n";
sendwifi(command);
}
void Command::sendRef(flying_status fs)
{
at = "AT*REF=";
if(fs == TAKEOFF){
command = at + getSequenceNumber() + ",290718208\r\n"; //takeoff
}
else if(fs == LANDING){
command = at + getSequenceNumber() + ",290717696\r\n"; //landing
} else if (fs == EMERGENCY_TOGGLE){
command = at + getSequenceNumber() + ",290717952\r\n"; //landing
}
// emergency -> 290717952
sendwifi(command);
}
void Command::send_control_commands(){
at = "AT*CTRL=";
sendwifi(at+getSequenceNumber()+",4,0\r\n");
sendwifi(at+getSequenceNumber()+",0,0\r\n");
sendwifi(at+getSequenceNumber()+",4,0\r\n");
}
void Command::drone_emergency_reset()
{
at = "AT*REF=";
command = at + getSequenceNumber() + ",290717952\r\n";
sendwifi(command);
}
/** Movement functions **/
int Command::moveForward(float distanceInMeters)
{
float i = 0;
String moveForward = makePcmd(1, 0, -.855, 0, 0);
delay(1000*distanceInMeters);
sendPcmd(moveForward);
return 1;
}
int Command::moveRotate(float yawInDegrees)
{
int i = 0;
while (i < yawInDegrees) {
String stayRotate = makePcmd(1, 0, 0, 0, 0.17);
sendPcmd(stayRotate);
delay(150);
i += 8;
}
return 1;
}
String Command::makePcmd(int enable, float roll, float pitch, float gaz, float yaw)
{
at = "AT*PCMD=";
command = at + getSequenceNumber() + "," + enable + "," + fl2int(roll) + "," + fl2int(pitch) + "," + fl2int(gaz) + "," + fl2int(yaw) + "\r";
return command;
}
void Command::sendPcmd(String command)
{
previousCommand = command;
sendwifi(command);
}
void Command::sendPcmd(int enable, float roll, float pitch, float gaz, float yaw)
{
at = "AT*PCMD=";
command = at + getSequenceNumber() + "," + enable + "," + fl2int(roll) + "," + fl2int(pitch) + "," + fl2int(gaz) + "," + fl2int(yaw) + "\r";
sendwifi(command);
}
String Command::makeAnim(anim_mayday_t anim, int time)
{
at = "AT*ANIM=";
command = at + getSequenceNumber() + "," + anim + "," + time + "\r\n";
return command;
}
void Command::doLEDAnim(int animseq, int duration)
{
PCsrl << "calling LEDAnim" << endl;
at = "AT*LED=";
command = at + getSequenceNumber() + "," + animseq + ",1073741824," + duration + "\r\n";
sendwifi(command);
}
int Command::start_s2ip()
{
char temp;
//delay(20000); //wait for drone to start
readARsrl();
if (debug) {
PCsrl << "trying to start s2ip" << endl;
}
ARsrl.print("\r\n");
delay(500);
ARsrl.print("\r\n");
delay(500);
ARsrl << "cd ~" << endl;
if (debug) {
readARsrl();
}
delay(500);
ARsrl << "cd data/video/apps/" << endl;
delay(500);
ARsrl << "./s2ip.arm" << endl;
while ((int) temp != 2) {
temp = ARsrl.read();
if (temp == 2) {
PCsrl << "s2ip is running" << endl;
ARsrl << "bullshit\r\n"; //to fix a delay bug
break;
}
//PCsrl << "s2ip not running" << endl;
}
if (debug) {
while (ARsrl.available()) {
PCsrl.write(ARsrl.read());
}
}
return 1;
}
void Command::quit_s2ip()
{
ARsrl.println("EXIT");
while (ARsrl.available()) {
PCsrl.write(ARsrl.read());
}
}
int Command::init_drone()
{
sendConfig("general:navdata_demo","TRUE");
sendConfig("control:altitude_max","2000");
sendConfig("control:euler_angle_max","0.35");
sendConfig("control:outdoor","FALSE");
sendConfig("control:flight_without_shell","FALSE");
send_control_commands();
sendComwdg_t(90);
sendFtrim();
drone_emergency_reset(); //clear emergency flag
return 1;
}
int Command::drone_takeoff()
{
sendRef(TAKEOFF);
int i = 0;
return 1;
}
int Command::drone_hover(int msec)
{
int i = 0;
while (i < msec) {
sendwifi(makePcmd(1, 0, 0, 0, 0));
delay(100);
i += 100;
}
return 1;
}
int Command::drone_landing()
{
sendRef(LANDING);
return 1;
}
int Command::drone_move_up(int centimeter)
{
int i = 0;
while (i < centimeter) {
ARsrl << makePcmd(1, 0, 0, 0.6, 0);
delay(100);
i += 10;
}
return 1;
}
int Command::drone_move_down(int centimeter)
{
int i = 0;
while (i < centimeter) {
sendwifi(makePcmd(1, 0, 0, -0.5, 0));
delay(100);
i += 10;
}
return 1;
}
long Command::fl2int(float value)
{
resultint.i = 0;
if (value < -1 || value > 1) {
resultint.f = 1;
} else {
resultint.f=value;
}
return resultint.i;
}
void Command::readARsrl()
{
while (ARsrl.available()) {
if (debug) {
PCsrl.write(ARsrl.read());
}
}
}
//Memory test code from : http://www.faludi.com/2007/04/18/arduino-available-memory-test/
int Command::memoryTest() {
int byteCounter = 0; // initialize a counter
byte *byteArray; // create a pointer to a byte array
// More on pointers here: http://en.wikipedia.org/wiki/Pointer#C_pointers
// use the malloc function to repeatedly attempt
// allocating a certain number of bytes to memory
// More on malloc here: http://en.wikipedia.org/wiki/Malloc
while ( (byteArray = (byte*) malloc (byteCounter * sizeof(byte))) != NULL ) {
byteCounter++; // if allocation was successful, then up the count for the next try
free(byteArray); // free memory after allocating it
}
free(byteArray); // also free memory after the function finishes
return byteCounter; // send back the highest number of bytes successfully allocated
}
int Command::getSequenceNumber(){
return sequenceNumber++;
}
// Volatile, since it is modified in an ISR.
volatile boolean inService = false;
void SrlRead()
{
if (inService) {
PCsrl.println("timer kicked too fast");
return;
}
interrupts();
inService = true;
while(ARsrl.available()) {
unsigned char k = ARsrl.read();
store_char(k, &rx_buf);
}
inService = false;
}
void read_rx_buf()
{
while (rx_buf.tail != rx_buf.head) {
if (debug) {
PCsrl.write(rx_buf.buffer[rx_buf.tail]);
}
rx_buf.tail = (unsigned int) (rx_buf.tail+ 1) % SERIAL_BUFFER_SIZE;
}
}
inline void store_char(unsigned char c, ring_buffer *buffer)
{
int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;
// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != buffer->tail) {
buffer->buffer[buffer->head] = c;
buffer->head = i;
}
else {
Serial.println("ring buffer is too small");
}
}
#endif
I know it sounds weird but, sometimes this happens when arduino is not getting enough power supply. Try connecting the arduino to a power source different from USB.
As soon as I started to put things in prog memory my program started to clear up it's hiccups. It seems it was a memory issue.
I had the same problem, but the issue was with Timer1.initialize(). Try this:
com.drone_is_init = com.init_drone();
Serial.println("One");
Serial.println("Two");
Serial.println("Three");
Timer1.initialize(COMWDG_INTERVAL_USEC);
Timer1.attachInterrupt(watchdog_timer);
Open serial monitor and see... it will show until "Two", and then Arduino will hang.
The issue was I calling some functions of the LiquidCrystal_I2C library, that need interrupt routines. Check if your timer ISR is using some interrupts. If so, you should move this code to another place in your project.