Task watchdog got triggered./abort() was called at PC 0x400de07b on core 0 - arduino-ide

I am on an Autonomous GPS robot project. When I am running the below code after some time the esp32(devkit v1) reboots and this goes on repeating.
Pause for Startup... 3
Pause for Startup... 2
Pause for Startup... 1
Searching for Satellites
Searching for Satellites
GPS Waypoint 1 Set Waypoint #1: 0.000000 , 0.000000
Waypoint #2: 0.000000 , 0.000000
5 Satellites Acquired10.190620
76.424872
25.190620
47.424872
YOYYYYO
Go to Waypoint
E (98333) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (98333) task_wdt: - async_tcp (CPU 0/1)
E (98333) task_wdt: Tasks currently running:
E (98333) task_wdt: CPU 0: IDLE0
E (98333) task_wdt: CPU 1: async_tcp
E (98333) task_wdt: Aborting.
abort() was called at PC 0x400de07b on core 0
Backtrace: 0x4008cbf8:0x3ffbe170 0x4008ce29:0x3ffbe190 0x400de07b:0x3ffbe1b0 0x40084f01:0x3ffbe1d0 0x40148e07:0x3ffbc0d0 0x400df42b:0x3ffbc0f0 0x4008ab01:0x3ffbc110 0x4008930d:0x3ffbc130
Rebooting...
ets Jun 8 2016 00:22:57
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:8896
load:0x40080400,len:5816
entry 0x400806ac
Welcome
Autonmous Mode Initiated...
IP Address: 192.168.1.18
Compass setting done
iam here1
Pause for Startup...
Pause for Startup... 10
Pause for Startup... 9
Pause for Startup... 8
YOYYYYO
Go to Waypoint
Pause for Startup... 7
Pause for Startup... 6
Pause for Startup... 5
Pause for Startup... 4
Pause for Startup... 3
E (10128) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (10128) task_wdt: - async_tcp (CPU 0)
E (10128) task_wdt: Tasks currently running:
E (10128) task_wdt: CPU 0: Tmr Svc
E (10128) task_wdt: CPU 1: IDLE1
E (10128) task_wdt: Aborting.
abort() was called at PC 0x400de07b on core 0
Backtrace: 0x4008cbf8:0x3ffbe170 0x4008ce29:0x3ffbe190 0x400de07b:0x3ffbe1b0 0x40084f01:0x3ffbe1d0 0x4000bfed:0x3ffbd060 0x4008a489:0x3ffbd070 0x400827d1:0x3ffbd090 0x40082843:0x3ffbd0b0 0x4008b825:0x3ffbd0d0 0x4008b924:0x3ffbd100 0x4008930d:0x3ffbd130
Rebooting...
ets Jun 8 2016 00:22:57
This is the msg that appears on the serial monitor. I tried debugging but can't find why this is happening.
The Code is really big, so I have uploaded only a part of it.
// CompaSerial Variables & Setup
HMC5883L compass;
int16_t mx, my, mz; // variables to store x,y,z axis from compass (HMC5883L)
int desired_heading; // initialize variable - stores value for the new desired heading
int compass_heading; // initialize variable - stores value calculated from compass readings
int compass_dev = 5; // the amount of deviation that is allowed in the compass heading - Adjust as Needed
// setting this variable too low will cause the robot to continuously pivot left and right
// setting this variable too high will cause the robot to veer off course
int Heading_A; // variable to store compass heading
int Heading_B; // variable to store compass heading in Opposite direction
int pass = 0; // variable to store which paSerial the robot is on
//*****************************************************************************************************
// GPS Locations
unsigned long Distance_To_Home; // variable for storing the distance to destination
int ac =0; // GPS array counter
int wpCount = 0; // GPS waypoint counter
double Home_LATarray[2]; // variable for storing the destination Latitude - Only Programmed for 5 waypoint
double Home_LONarray[2]; // variable for storing the destination Longitude - up to 50 waypoints
int increment = 0;
//*****************************************************************************************************
// HTML Page
AsyncWebServer server(80);
const char* ssid = "******";
const char* password = "******";
const char* PARAM_INPUT_1 = "input1";
const char* PARAM_INPUT_2 = "input2";
const char* PARAM_INPUT_3 = "input3";
const char* PARAM_INPUT_4 = "input4";
const char* PARAM_COMMIT = "commit";
double lati1;
double logi1;
double lati2;
double logi2;
// HTML web page to handle 4 input fields
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html>
<head>
<h2>Autonomus GPS Robot Car<h2>
<h3> Submit your Destination coordinates</h3>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<style>
a {
border: 10px solid powderblue;
padding: 10px;
color: red;
font-family: verdana;
font-size: 150%;
}
</style>
</head>
<body>
<form action="/get" >
<br>
Waypoint 1 Latitude : <input type="text" name="input1">
<br>
<br>
Waypoint 1 Longitude: <input type="text" name="input2">
<br><br>
<br>
Waypoint 2 Latitude : <input type="text" name="input3">
<br>
<br>
Waypoint 2 Longitude: <input type="text" name="input4">
<br><br>
<input type="submit" value="Submit">
<br>
<br><br>
<br><br>
<a href="/go" >Go to Destination</a>
<br><br> <br><br>
<br><br>
<a href="/clear" > Clear waypoints</a>
</form>
</body>
</html>)rawliteral";
void notFound(AsyncWebServerRequest *request) {
request->send(404, "text/plain", "Not found");
}
//*****************************************************************************************************
// Extras
#define autopilot 18
void gesturecontroll();
void getGPS();
void getCompass();
void Forward();
void Forward_Meter();
void Reverse();
void LeftTurn();
void RightTurn();
void SlowLeftTurn();
void SlowRightTurn();
void StopCar();
void setWaypoint();
void move();
void Startup();
void goWaypoint();
void clearWaypoints();
int blueToothVal;
int flag=0;
int button;
void setup()
{ Serial.begin(115200); // Serial 0 is for communication with the computer
Serial.println("Welcome");
pinMode(autopilot, INPUT);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
button = digitalRead(autopilot);
if (button == HIGH)
{ flag=15;
Serial.println("Manual Control initated");
Serial.println("ESPNow/Basic/Slave Example");
//Set device in AP mode to begin with
WiFi.mode(WIFI_AP);
// configure device AP mode
// This is the mac address of the Slave in AP Mode
esp_wifi_set_mac(ESP_IF_WIFI_STA, &mac[0]);
Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
// Init ESPNow with a fallback logic
if (esp_now_init()!=0)
{
Serial.println("*** ESP_Now init failed");
while(true) {};
}
// Once ESPNow is successfully Init, we will register for recv CB to
// get recv packer info.
esp_now_register_recv_cb(OnDataRecv);
Serial.print("Aheloiioi"); // the remaining code for above part is not uploaded since when switch is pulled this part of code works perfectly
}
else{
S2.begin(9600, SERIAL_8N1, RXPin, TXPin); // Serial 2 is for GPS communication at 9600 baud - DO NOT MODIFY - Ublox Neo 6m
flag=0;
// pinMode(LED_BUILTIN, OUTPUT); // An LED indicator - Not Used
Serial.println("Autonmous Mode Initiated...");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Failed!");
return;
}
Serial.println();
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
CompaSerial////////////////////////////////////////////////////////////////////////////////////
Wire.begin(); // Join I2C bus used for the HMC5883L compass
//compass.init();
compass.begin(); // initialize the compass (HMC5883L)
compass.setRange(HMC5883L_RANGE_1_3GA); // Set measurement range
compass.setMeasurementMode(HMC5883L_CONTINOUS); // Set measurement mode
compass.setDataRate(HMC5883L_DATARATE_30HZ); // Set data rate
compass.setSamples(HMC5883L_SAMPLES_8); // Set number of samples averaged
compass.setOffset(0,0);
Serial.println("Compass setting done");
Startup(); // Run the Startup procedure on power-up one time
}
}
// Main Loop
void loop()
{ button = digitalRead(autopilot);
if (button == HIGH && flag==15)
{
}
else
{ Coordinates();
getGPS(); // Update the GPS location
getCompass(); // Update the CompaSerial Heading
//Ping(); // Use at your own discretion, this is not fully tested
}
}
void Coordinates()
{ Serial.println("i am here1");
// Send web page with input fields to client
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html);
});
// Send a GET request to <ESP_IP>/get?input1=<inputMessage>
server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
String latitude1;
String latitude1Param;
String longitude1;
String longitude1Param;
String latitude2;
String latitude2Param;
String longitude2;
String longitude2Param;
String commitType;;
if (request->hasParam(PARAM_INPUT_2)||request->hasParam(PARAM_INPUT_1) ) {
// GET input1 value on <ESP_IP>/get?input1=<latitude>
latitude1 = request->getParam(PARAM_INPUT_1)->value();
latitude1Param = PARAM_INPUT_1;
// GET input2 value on <ESP_IP>/get?input2=<longitude>
longitude1 = request->getParam(PARAM_INPUT_2)->value();
longitude1Param = PARAM_INPUT_2;
// GET input3 value on <ESP_IP>/get?input3=<latitude>
latitude2 = request->getParam(PARAM_INPUT_3)->value();
latitude2Param = PARAM_INPUT_3;
// GET input4 value on <ESP_IP>/get?input4=<longitude>
longitude2 = request->getParam(PARAM_INPUT_4)->value();
longitude2Param = PARAM_INPUT_4;
}
else {
latitude1 = "No message sent";
latitude1Param = "none";
longitude1 = "No message sent";
longitude1Param = "none";
latitude2 = "No message sent";
latitude2Param = "none";
longitude2 = "No message sent";
longitude2Param = "none";
}
Serial.println(latitude1);
Serial.println(longitude1);
Serial.println(latitude2);
Serial.println(longitude2);
lati1=(latitude1.toFloat());
logi1=(longitude1.toFloat());
lati2=(latitude2.toFloat());
logi2=(longitude2.toFloat());
//Serial.println(lati,6);
//Serial.println(logi,6);
request->send(200, "text/html", "Command succesfuly sent""<br>Return to Home Page");
});
server.on("/go", HTTP_GET, [] (AsyncWebServerRequest *request) {
//logic for go here
Serial.println("YOYYYYO");
goWaypoint();
request->redirect("/");
});
server.on("/clear", HTTP_GET, [] (AsyncWebServerRequest *request) {
//logic for clear here
Serial.println("fdfghgh");
clearWaypoints();
request->redirect("/");
});
server.onNotFound(notFound);
server.begin();
}
void getGPS() // Get Latest GPS coordinates
{ Serial.println("i am here2");
while (S2.available() > 0)
gps.encode(S2.read());
}
// *************************************************************************************************************************************************
void setWaypoint() // Set up to 5 GPS waypoints
{
//if ((wpCount >= 0) && (wpCount < 50))
if (wpCount >= 0)
{
Serial.print("GPS Waypoint ");
Serial.print(wpCount + 1);
Serial.print(" Set ");
Home_LATarray[ac] = lati1 ; // store waypoint in an array
Home_LONarray[ac] = logi1 ; // store waypoint in an array
Home_LATarray[ac] = lati2 ; // store waypoint in an array
Home_LONarray[ac] = logi2 ; // store waypoint in an array
Serial.print("Waypoint #1: ");
Serial.print(Home_LATarray[0],6);
Serial.print(" , ");
Serial.println(Home_LONarray[0],6);
Serial.print("Waypoint #2: ");
Serial.print(Home_LATarray[1],6);
Serial.print(" , ");
Serial.println(Home_LONarray[1],6);
wpCount++; // increment waypoint counter
ac++; // increment array counter
}
else {Serial.print("Waypoints Full");}
}
// *************************************************************************************************************************************************
void clearWaypoints()
{
memset(Home_LATarray, 0, sizeof(Home_LATarray)); // clear the array
memset(Home_LONarray, 0, sizeof(Home_LONarray)); // clear the array
wpCount = 0; // reset increment counter to 0
ac = 0;
Serial.print("GPS Waypoints Cleared"); // display waypoints cleared
}
// *************************************************************************************************************************************************
void getCompass() // get latest compass value
{
Vector norm = compass.readNormalize();
// Calculate heading
float heading = atan2(norm.YAxis, norm.XAxis);
if(heading < 0)
heading += 2 * M_PI;
compass_heading = (int)(heading * 180/M_PI); // aSerialign compass calculation to variable (compass_heading) and convert to integer to remove decimal places
}
void Startup()
{
Serial.println("Pause for Startup... ");
for (int i=10; i >= 1; i--) // Count down for X seconds
{
Serial.print("Pause for Startup... ");
Serial.println(i);
delay(1000); // Delay for X seconds
}
Serial.println("Searching for Satellites ");
Serial.println("Searching for Satellites ");
while (Number_of_SATS <= 4) // Wait until x number of satellites are acquired before starting main loop
{
getGPS(); // Update gps data
Number_of_SATS = (int)(gps.satellites.value()); // Query Tiny GPS for the number of Satellites Acquired
}
setWaypoint(); // set intial waypoint to current location
wpCount = 0; // zero waypoint counter
ac = 0; // zero array counter
Serial.print(Number_of_SATS);
Serial.print(" Satellites Acquired");
}
void goWaypoint()
{
Serial.println("Go to Waypoint");
//Serial.print("Home_Latarray ");
//Serial.print(Home_LATarray[ac],6);
//Serial.print(" ");
//Serial.println(Home_LONarray[ac],6);
//Serial1.print("Distance to Home");
//Serial1.print(Distance_To_Home);
//Serial1.print("ac= ");
//Serial1.print(ac);
while (true)
{ // Start of Go_Home procedure
// bluetooth(); // Run the Bluetooth procedure to see if there is any data being sent via BT
if (blueToothVal == 5){break;} // If a 'Stop' Bluetooth command is received then break from the Loop
getCompass(); // Update Compass heading
getGPS(); // Tiny GPS function that retrieves GPS data - update GPS location// delay time changed from 100 to 10
if (millis() > 5000 && gps.charsProcessed() < 10) // If no Data from GPS within 5 seconds then send error
Serial.println(F("No GPS data: check wiring"));
Distance_To_Home = TinyGPSPlus::distanceBetween(gps.location.lat(),gps.location.lng(),Home_LATarray[ac], Home_LONarray[ac]); //Query Tiny GPS for Distance to Destination
GPS_Course = TinyGPSPlus::courseTo(gps.location.lat(),gps.location.lng(),Home_LATarray[ac],Home_LONarray[ac]); //Query Tiny GPS for Course to Destination
/*
if (Home_LATarray[ac] == 0) {
Serial1.print("End of Waypoints");
StopCar();
break;
}
*/
if (Distance_To_Home == 0) // If the Vehicle has reached it's Destination, then Stop
{
StopCar(); // Stop the robot after each waypoint is reached
Serial.println("You have arrived!"); // Print to Bluetooth device - "You have arrived"
ac++; // increment counter for next waypoint
break; // Break from Go_Home procedure and send control back to the Void Loop
// go to next waypoint
}
if ( abs(GPS_Course - compass_heading) <= 15) // If GPS Course and the Compass Heading are within x degrees of each other then go Forward
// otherwise find the shortest turn radius and turn left or right
{
Forward(); // Go Forward
} else
{
int x = (GPS_Course - 360); // x = the GPS desired heading - 360
int y = (compass_heading - (x)); // y = the Compass heading - x
int z = (y - 360); // z = y - 360
if ((z <= 180) && (z >= 0)) // if z is less than 180 and not a negative value then turn left otherwise turn right
{ SlowLeftTurn(); }
else { SlowRightTurn(); }
}
} // End of While Loop
}

wdt is the watchdog timer. It's a timer that is used to detect whether your code has crashed. If it's not reset periodically it will throw an error and restart the ESP32. The timer needs to be reset frequently.
Notice that the error says that it was the async_tcp task which was running when the watchdog timer trigger. You're using the AsyncWeb server, which uses async_tcp.
When the async web server gets a page request, it calls your code. You have handlers for individual pages. Those handlers need to treat the calls to them the way we have to deal with loop() - if you spend 3 seconds or more without returning or calling delay() or yield(). This gives the underlying software the chance to reset the watchdog timer.
Review your web page handlers. Look for where you may spend a long time in them.
You'll find that you call goWayPoint() in your handler for '/go'. It has a loop in it that may block for 5 seconds. 5 seconds is too long - if that loop doesn't return or call delay() the watchdog timer will fire, which it does.
The easy fix is to add a call to delay() in the while(true) loop.
while (true)
{
delay(1);
this will let the underlying code reset the watchdog timer.
That won't help if other parts of your code (getCompass(), getGPS() or other things) take too long.
Ultimately you should refactor your code. You're doing too much work in the web server callbacks. That work should be done in independent tasks - perhaps in loop(). But that's a big project. Adding a call to delay(1) anywhere in a web server callback that you have a while loop or make take some time to do some processing is clumsy but should solve this problem.

Welcome to the String heap fracturing club:
String latitude1;
String latitude1Param;
String longitude1;
String longitude1Param;
String latitude2;
String latitude2Param;
String longitude2;
String longitude2Param;
String commitType;;
in combination with async webserver is a huge problem. I rewrote a ~15.000 lines application to get rid of strings (also in the used libraries) and since then no resets and reboots anymore. Hope this helps you in your project.
Use predifined fixed char arrays they will go to the stack and keep heap corruption low.Use functions like strcpy, strcat, itoa / atoi to build messages or retrieve values.
EDIT: replace String class with fixed char arrays example
char numBuffer [16] ={'\0'} // For 15 chars and the null terminator
char latitude1 [32] ={'\0'} // For 31 chars and the null terminator
.... some code here ....
strcpy (latitude1 , "No values here");
//or
strcpy (latitude1 , "Value 1: ");
itoa (SomeIntDataNumber, numBuffer,10);
strcat (latitude1, numBuffer) // append the converted SomeIntDataNumber
One more thing if you use memset, make sure you do proper memory management, also check the used libraries for heavy use of String class. Some libs work in a static environment quite well, using them in a web context crashes the ESP. I had to ditch some libs or at least rewrite them without String class.
Further reading: https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/
Final Tip: Try to commenting out / replacing with dummy chars all appearancies of the String class and try the code again.

ESP-IDF creats a watchdog timer for idle tasks in addition to any tasks doing your work. IE, it creates two extra tasks IDLE0 & IDLE 1 (one for each core), whose sole purpose is to do nothing, ie idle. These idle tasks simply feed the watchdog whenever its respective core is idling. Whenever any task, in Arduino or in ESP-IDF, as well as interrupt routines, run with a higher priority than the IDLE tasks without delaying or blocking sufficiently long/often enough (such as when executing in a tight while loop), it triggers the watchdog, because that core is now fully busy, meaning it is no longer idling often enough, meaning the idle "tasks" get starved, so they can't reset the watchdog. Your app_main() in ESP-IDF and loop() in Arduino, run with higher priorities than the IDLE tasks. This is the source of the problem.
You either have to make some call that blocks your code for atleast 10mS in sufficient intervals, or you have to call yield() or
vTaskDelay(NUMBER_OF_MILLISECONDS_TO_DELAY / portTICK_PERIOD_MS)
with a minimum of 10mS (otherwise, due to discreteness, it amounts to 0, ie no delay at all, thus won't work. You can work around this by increasing the scheduler frequency).
An alternative is fully disabling the watchdog, but this nullifies its uses.
There is a more elegant solution. If you do need something to consume all available CPU time, and don't want to bother with considerations of delay or blocking, and don't want to disable the watchdog, but don't want it to bark, then put all intensive code operations in its own function or set of functions, and call it/each using the following task creation function:
xTaskCreate(someFunction, "HumanReadableNameofTask", 4096, NULL, tskIDLE_PRIORITY, NULL);
where your function has the following signature:
void someFunction(void* arg)
This won't trip the watchdog no matter what, because it uses the tskIDLE_PRIORITY priority. I'm not sure what value it has, but it seems greater than 10, because I tried 10 and it didn't work. Not sure if 11 did, which would be lower priority than the IDLE tasks. Note though, any code you place in someFunction(), won't execute at all except during times when the CPU is IDLE. So all your other code must still sleep/delay/block sufficiently enough to give it time to run. This is the ideal place for endless intensive code, such as motor control and PID control loops.
You can even do this in Arduino.

Related

C - pass array as parameter and change size and content

UPDATE: I solved my problem (scroll down).
I'm writing a small C program and I want to do the following:
The program is connected to a mysql database (that works perfectly) and I want to do something with the data from the database. I get about 20-25 rows per query and I created my own struct, which should contain the information from each row of the query.
So my struct looks like this:
typedef struct {
int timestamp;
double rate;
char* market;
char* currency;
} Rate;
I want to pass an empty array to a function, the function should calculate the size for the array based on the returned number of rows of the query. E.g. there are 20 rows which are returned from a single SQL query, so the array should contain 20 objectes of my Rate struct.
I want something like this:
int main(int argc, char **argv)
{
Rate *rates = ?; // don't know how to initialize it
(void) do_something_with_rates(&rates);
// the size here should be ~20
printf("size of rates: %d", sizeof(rates)/sizeof(Rate));
}
How does the function do_something_with_rates(Rate **rates) have to look like?
EDIT: I did it as Alex said, I made my function return the size of the array as size_t and passed my array to the function as Rate **rates.
In the function you can access and change the values like (*rates)[i].timestamp = 123 for example.
In C, memory is either dynamically or statically allocated.
Something like int fifty_numbers[50] is statically allocated. The size is 50 integers no matter what, so the compiler knows how big the array is in bytes. sizeof(fifty_numbers) will give you 200 bytes here.
Dynamic allocation: int *bunch_of_numbers = malloc(sizeof(int) * varying_size). As you can see, varying_size is not constant, so the compiler can't figure out how big the array is without executing the program. sizeof(bunch_of_numbers) gives you 4 bytes on a 32 bit system, or 8 bytes on a 64 bit system. The only one that know how big the array is would be the programmer. In your case, it's whoever wrote do_something_with_rates(), but you're discarding that information by either not returning it, or taking a size parameter.
It's not clear how do_something_with_rates() was declared exactly, but something like: void do_something_with_rates(Rate **rates) won't work as the function has no idea how big rates is. I recommend something like: void do_something_with_rates(size_t array_size, Rate **rates). At any rate, going by your requirements, it's still a ways away from working. Possible solutions are below:
You need to either return the new array's size:
size_t do_something_with_rates(size_t old_array_size, Rate **rates) {
Rate **new_rates;
*new_rates = malloc(sizeof(Rate) * n); // allocate n Rate objects
// carry out your operation on new_rates
// modifying rates
free(*rates); // releasing the memory taken up by the old array
*rates = *new_rates // make it point to the new array
return n; // returning the new size so that the caller knows
}
int main() {
Rate *rates = malloc(sizeof(Rate) * 20);
size_t new_size = do_something_with_rates(20, &rates);
// now new_size holds the size of the new array, which may or may not be 20
return 0;
}
Or pass in a size parameter for the function to set:
void do_something_with_rates(size_t old_array_size, size_t *new_array_size, Rate **rates) {
Rate **new_rates;
*new_rates = malloc(sizeof(Rate) * n); // allocate n Rate objects
*new_array_size = n; // setting the new size so that the caller knows
// carry out your operation on new_rates
// modifying rates
free(*rates); // releasing the memory taken up by the old array
*rates = *new_rates // make it point to the new array
}
int main() {
Rate *rates = malloc(sizeof(Rate) * 20);
size_t new_size;
do_something_with_rates(20, &new_size, &rates);
// now new_size holds the size of the new array, which may or may not be 20
return 0;
}
Why do I need to pass the old size as a parameter?
void do_something_with_rates(Rate **rates) {
// You don't know what n is. How would you
// know how many rate objects the caller wants
// you to process for any given call to this?
for (size_t i = 0; i < n; ++i)
// carry out your operation on new_rates
}
Everything changes when you have a size parameter:
void do_something_with_rates(size_t size, Rate **rates) {
for (size_t i = 0; i < size; ++i) // Now you know when to stop
// carry out your operation on new_rates
}
This is a very fundamental flaw with your program.
I want to also want the function to change the contents of the array:
size_t do_something_with_rates(size_t old_array_size, Rate **rates) {
Rate **new_rates;
*new_rates = malloc(sizeof(Rate) * n); // allocate n Rate objects
// carry out some operation on new_rates
Rate *array = *new_rates;
for (size_t i = 0; i < n; ++i) {
array[i]->timestamp = time();
// you can see the pattern
}
return n; // returning the new size so that the caller knows
}
sizeof produces a value (or code to produce a value) of the size of a type or the type of an expression at compile time. The size of an expression can therefore not change during the execution of the program. If you want that feature, use a variable, terminal value or a different programming language. Your choice. Whatever. C's better than Java.
char foo[42];
foo has either static storage duration (which is only partially related to the static keyword) or automatic storage duration.
Objects with static storage duration exist from the start of the program to the termination. Those global variables are technically called variables declared at file scope that have static storage duration and internal linkage.
Objects with automatic storage duration exist from the beginning of their initialisation to the return of the function. These are usually on the stack, though they could just as easily be on the graph. They're variables declared at block scope that have automatic storage duration and internal linkage.
In either case, todays compilers will encode 42 into the machine code. I suppose it'd be possible to modify the machine code, though that several thousands of lines you put into that task would be much better invested into storing the size externally (see other answer/s), and this isn't really a C question. If you really want to look into this, the only examples I can think of that change their own machine code are viruses... How are you going to avoid that antivirus heuristic?
Another option is to encode size information into a struct, use a flexible array member and then you can carry both the array and the size around as one allocation. Sorry, this is as close as you'll get to what you want. e.g.
struct T_vector {
size_t size;
T value[];
};
struct T_vector *T_make(struct T_vector **v) {
size_t index = *v ? (*v)->size++ : 0, size = index + 1;
if ((index & size) == 0) {
void *temp = realloc(*v, size * sizeof *(*v)->value);
if (!temp) {
return NULL;
}
*v = temp;
// (*v)->size = size;
*v = 42; // keep reading for a free cookie
}
return (*v)->value + index;
}
#define T_size(v) ((v) == NULL ? 0 : (v)->size)
int main(void) {
struct T_vector *v = NULL; T_size(v) == 0;
{ T *x = T_make(&v); x->value[0]; T_size(v) == 1;
x->y = y->x; }
{ T *y = T_make(&v); x->value[1]; T_size(v) == 2;
y->x = x->y; }
free(v);
}
Disclaimer: I only wrote this as an example; I don't intend to test or maintain it unless the intent of the example suffers drastically. If you want something I've thoroughly tested, use my push_back.
This may seem innocent, yet even with that disclaimer and this upcoming warning I'll likely see a comment along the lines of: Each successive call to make_T may render previously returned pointers invalid... True, and I can't think of much more I could do about that. I would advise calling make_T, modifying the value pointed at by the return value and discarding that pointer, as I've done above (rather explicitly).
Some compilers might even allow you to #define sizeof(x) T_size(x)... I'm joking; don't do this. Do it, mate; it's awesome!
Technically we aren't changing the size of an array here; we're allocating ahead of time and where necessary, reallocating and copying to a larger array. It might seem appealing to abstract allocation away this way in C at times... enjoy :)

Outputting a bitstream onto a pin in verilog

I need to output a 32bit bit-stream onto a pin in verilog. I know verilog has the streaming operators pack and unpack but I do not believe they will do what I want it to do.
I have 32x512 FIFO RAM in which data is stored. Data for the variable "I" stored on the first 32 bits and the data for variable "Q" is stored on the next 32 bits (the rest of FIFO saves data in this alternating fashion). I need to continually get a 32bit stream off the FIFO RAM and output the 32bit data stream onto a pin. My FIFO has three output signals(a signal for the 32 bit data stream(32_data), a signal to say when the FIFO is empty (32_empty), and a signal to say when the FIFO is full(32_full)) My sudo code is the following (It's sudo code because I know how to do everything else but the part I need help with and I wanted to keep it simple for understanding):
process # posedge clock
begin
if (32_empty != 1) then //if the FIFO has data
if (32_full == 1) then //if the FIFO is full, then we lose data (for testing purposes to know if I need to make the RAM bigger
PIN_1 <= 1; //output onto a pin that the FIFO is full
PIN_2 <= 0; //clear pin 2 from outputting data for "I"
PIN_3 <= 0; //clear pin 3 from outputting data for "Q"
else if (en_Q == 0)
(stream 32bit data for variable "I" onto pin 2) //variable "I" output//HELP-This is where I need help figuring out how to stream the output, 32_data, onto a pin
en_Q <= ~en_Q; // toggle en_Q so next 32bit stream will be for "Q"
else if (en_Q ==1)
(stream 32bit data for variable "Q" onto pin 3) //variable "Q" output//HELP-This is where I need help figuring out how to stream the output, 32_data, onto a pin
en_Q <= ~en_Q; // toggle en_Q so next 32bit stream will be for "I"
end
If you could help me with figuring out how to stream a 32 bit data stream onto a pin, that would be great!
Thanks in advance
I have added the suggestion. Could I put the data on the pins with a for loop? The following is my code segment and the bottom part is the shift register and outputting to a pin:
`// Wires and registers related to data capturing
wire capture_clk;
reg [31:0] capture_data;
wire capture_en;
reg [4:0] slowdown;
wire capture_full;
reg capture_open;
reg capture_open_cross;
reg capture_has_been_full;
reg capture_has_been_nonfull;
reg has_been_full_cross;
reg has_been_full;
// Data capture section
// ====================
always #(posedge capture_clk)
begin
if (capture_en)
capture_data <= user_w_write_32_data; // Bogus data source
// The slowdown register limits the data pace to 1/32 the bus_clk
// when capture_clk = bus_clk. This is necessary, because the
// core in the evaluation kit is configured for simplicity, and
// not for performance. Sustained data rates of 200 MB/sec are
// easily reached with performance-oriented setting.
// The slowdown register has no function in a real-life application.
slowdown <= slowdown + 1;
// capture_has_been_full remembers that the FIFO has been full
// until the file is closed. capture_has_been_nonfull prevents
// capture_has_been_full to respond to the initial full condition
// every FIFO displays on reset.
if (!capture_full)
capture_has_been_nonfull <= 1;
else if (!capture_open)
capture_has_been_nonfull <= 0;
if (capture_full && capture_has_been_nonfull)
capture_has_been_full <= 1;
else if (!capture_open)
capture_has_been_full <= 0;
end
// The dependency on slowdown is only for bogus data
assign capture_en = capture_open && !capture_full &&
!capture_has_been_full &&
(slowdown == 0);
// Clock crossing logic: bus_clk -> capture_clk
always #(posedge capture_clk)
begin
capture_open_cross <= user_r_read_32_open;
capture_open <= capture_open_cross;
end
// Clock crossing logic: capture_clk -> bus_clk
always #(posedge bus_clk)
begin
has_been_full_cross <= capture_has_been_full;
has_been_full <= has_been_full_cross;
end
// The user_r_read_32_eof signal is required to go from '0' to '1' only on
// a clock cycle following an asserted read enable, according to Xillybus'
// core API. This is assured, since it's a logical AND between
// user_r_read_32_empty and has_been_full. has_been_full goes high when the
// FIFO is full, so it's guaranteed that user_r_read_32_empty is low when
// that happens. On the other hand, user_r_read_32_empty is a FIFO's empty
// signal, which naturally meets the requirement.
assign user_r_read_32_eof = user_r_read_32_empty && has_been_full;
assign user_w_write_32_full = 0;
// The data capture clock here is bus_clk for simplicity, but clock domain
// crossing is done properly, so capture_clk can be an independent clock
// without any other changes.
assign capture_clk = bus_clk;
async_fifo_32x512 fifo_32 //FIFO created using Xilinx FIFO Generator Wizard
(
.rst(!user_r_read_32_open),
.wr_clk(capture_clk),
.rd_clk(bus_clk),
.din(capture_data),
.wr_en(capture_en),
.rd_en(user_r_read_32_rden),
.dout(user_r_read_32_data),
.full(capture_full),
.empty(user_r_read_32_empty)
);
reg Q_en = 1'b0; //starting value is 0 because first 32bit is I
reg [31:0] data_outI;
reg [31:0] data_outQ;
reg I;
reg Q;
integer counter;
always #(posedge bus_clk) begin
if(Q_en == 1'b0) begin //To output to I signal
data_outI <= user_r_read_32_data;
for (counter = 0; counter < 32; counter = counter + 1) begin //output to pins
I = data_outI[0];
data_outI <= (data_outI >> 1);
Q = data_outQ[0];
data_outQ <= (data_outQ >> 1);
end
Q_en <= ~Q_en;
end
else if(Q_en == 1'b1) begin //To output to Q signal
data_outQ <= user_r_read_32_data;
for (counter = 0; counter < 32; counter = counter + 1) begin //output to pins
I = data_outI[0];
data_outI <= (data_outI >> 1);
Q = data_outQ[0];
data_outQ <= (data_outQ >> 1);
end
Q_en <= ~Q_en;
end
end
assign PS_GPIO_ONE_I = I; //Assign Pin I
assign PS_GPIO_TWO_Q = Q; //Assign Pin Q
`
Basically, you'd want to do something like the following:
Fetch an item from the fifo into a 32 bit register (lets call data)
Each clock cycle, put the lsb of data onto the pin, and then right shift data by one value.
Keep repeating this shifting for 32 clock cycles, until all of the data has been shifted out.
Toggle the value of en_Q, and fetch another 32 bit item.
You should be able to make a small state machine that can handle this sequence. You can't shift out all 32 bits in a single clock cycle as you have done in your pseudo-code, unless you also have a 32x clock available, and that would likely be a more complicated design.

Actionscript3 to Arduino: sending a 'newline' character after an array of integers

I want to send an array of integers from an as3 app I'm writing in Flash Pro, to an Arduino Uno which will use them to continuously position and re-position 5 servos. So sending 15 integers will position the 5 servos, then re-position them, then reposition them again, then loop back to the first position and so on. Then I would send a new array replacing the old one whenever I wanted to.
So I've got my tinkerproxy configured between them ok (thanks to Mike Chambers and others) and I've written both sides so they appear to work ok when interfacing with their serial monitors. But I can't get em talking to each other properly.
My problem is simple ... I think ... It's how to get as3 to send a 'newline' or some other 'end' signal with or after the array so that the Arduino sketch (using serialEvent and parseInt to get the integers when they are sent), on receiving it, can jump past parseInt and do something else - in this case go to the loop and control these pesky servos.
Probably far too much code attached and I hope somebody can help. I'm pretty inexperienced, you may have guessed....
ARDUINO
/*
this sketch developed from arduino Tutorials ReadASCIIString + SerialEvent
serialEvent can receive an array - 'buff' - of values from serial monitor
loop can get those values and print some of them to prove it
but I can't get Flash Pro (as3) to send the array: something to do with end of message character?
*/
#include <Servo.h>
int buff[100];//an array to hold integers from serial(arbitrary larger than ever needed size)
int j; //used to increment serial integer receipt in serialEvent
int patternLength;//=# of integers delivered over serial port, if followed by E or newline
void setup()
{
Serial.begin(9600);
Serial.setTimeout(2147483647);//25 days! so parseInt doesn't default to sending zeros every second
Serial.println("ready to go");//prints ok
}
void loop()
{
for(int i=0; i<patternLength-4; i=i+5)//feed sets of 5 integers into 5 servos then repeats
Serial.println(buff[i]);//prints 1st, 5th, 10th etc integer then repeats
delay(1000);//so I can see it happening slowly enough
}//loops indefinitely until serialEvent interrupts to send new buff array values
void serialEvent()
{
while(Serial.available()>0)
{
buff[j] = Serial.parseInt();
Serial.println(buff[j]);//prints all integers sent if eg ','sent after last one
j++;
//if (Serial.read() == '\n')//works if serial monitor is set to 'newline' on sending
if (Serial.read() == 'E')//works if no 'newline' + sending eg 1,2,3,4,5,6,7,8,9,10E
//BUT how to send the equivalent of one of the above two 'endings' from Flash???
//so that this part of the code executes
{
patternLength = j;
Serial.println("go to loop");
j=0;//reset the index so next array sent replaces this one in 'buff'
}
}
}
FLASH PRO ACTIONSCRIPT as3
/*
Simple Example that connects to an Arduino (via TinkerProxy) and sends
an array of integers for it to use. That doesn't work......
adapted from FlashBlink Created by Mike Chambers:
http://www.mikechambers.com/blog/2010/08/04/getting-started-with-flash-and-arduino/
*/
import flash.events.Event;
import flash.display.Sprite;
import flash.net.Socket;
//import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
//import flash.events.SecurityErrorEvent;
import flash.utils.Endian;
import flash.events.MouseEvent;
//my example of an array of integers I want to send to the arduino
var pattern:Array = [10,11,12,13,14,15,16,17,18,19,20];
//socket we will use to connect to TinkerProxy
var _socket:Socket;
//Address where TinkerProxy is located. Will usually be
//localhost / 127.0.0.1
var _proxyAddress:String = "127.0.0.1";
//port TinkerProxy is listening on
var _proxyPort:uint = 5331;
function onAddedToStage():void
{
removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
//create a Sprite to add to the stage.
//This will be a simple button
var s:Sprite = new Sprite();
//draw a green square in the Sprite
s.graphics.beginFill(0x00FF00);
s.graphics.drawRect(0,0, 200,100);
s.graphics.endFill();
//Add Sprite to the display list
addChild(s);
//position it
s.x = 50;
s.y = 50;
//listen for when the user clicks the Sprite
s.addEventListener(MouseEvent.CLICK, onClick);
_socket = new Socket();
//Register for socket events
//socket connected
_socket.addEventListener( Event.CONNECT, onConnect );
//socket closed
_socket.addEventListener( Event.CLOSE, onClose );
_socket.endian = Endian.LITTLE_ENDIAN;
//connect
_socket.connect(_proxyAddress, _proxyPort);
}
//called when we connect to the proxy server
function onConnect(event:Event):void
{
trace("Socket Connected");
}
//called when the user clicks the button on stage
function onClick(event:MouseEvent):void
{
trace("onClick");
//make sure we are connected to the socket
if(!_socket.connected)
{
//if not, don't do anything
trace("You must be connected to send a command to the Arduino.");
return;
}
var ENDOF:String = "E";
for(var j:int = 0; j < pattern.length; j++)
{
_socket.writeUTFBytes(pattern[j]); //send pattern array to Arduino
trace(pattern[j]);//trace what I think I've just sent
}
//then send something as a last character - not an integer.
_socket.writeUTFBytes(ENDOF);//send this string value to arduino
trace("should have just sent an E, and sends an: " + ENDOF);
//but how do I send this E conjoined to the last integer of the pattern array
//so that Arduino responds by jumping out of serialEvent back to the loop?
//flush the socket. Not really necessary, but here for forward compatibility.
_socket.flush();
}
//called when the socket is closed
function onClose(event:Event):void
{
trace("Socket Closed");
}
onAddedToStage();
Your AS3 looks fairly spot on. One minor point, in onAddedToStage() you're removing an event listener from the stage which you never registered for. If you really want that code to only fire once the timeline is added to the stage, replace line 114 with with following:
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage)
As for your Arduino code , I'm not versed in the language it uses (some sort of C?), so feel free to ignore the following if you know better.
You didn't encapsulate your for loop on lines 22 thru 24
You started encapsulating your while loop on line 30, but forgot to close it on line 34
You declared j, but didn't initialized its value until line 44 after it was to be used in your while loop on line 33.
Finally, to answer your core question. You're already aware a newline is written as \n, so it would seem you're having difficulty reading this from Serial.read(). After reading the documentation, I couldn't find any datatype it comes out as, so I'm assuming you're dealing with either a ByteArray or a String. Assuming it's a string, my first instinct would be to just split it into an Array with String.split(), but that's not a function available to String API. Others (however) have written it, and I believe it would simplify the issue, assuming Strings & Ints can happily co-exist in those object types.
Conversely, since you already know the size of these numbers come in quintets, rather than use a while loop (line 29), you could just use a for as follows:
#include <Servo.h>
int buff[100];
int j;
int patternLength;
void setup() {
Serial.begin(9600);
Serial.setTimeout(2147483647);
Serial.println("ready to go");
}
void loop() {
for(int i=0; i<patternLength-4; i=i+5) {
Serial.println(buff[i]);
delay(1000);
}
}
void serialEvent() {
if (Serial.available() > 0) {
// This gaurantees we only pull the first 15 Ints into our buff array
for (int k=0; k<15; k++) {
buff[j] = Serial.parseInt();
Serial.println(buff[j]);
j++;
}
patternLength = j;
Serial.println("go to loop");
j=0;//reset the index so next array sent replaces this one in 'buff'
}
}
If the above misses the mark for you, you may want to debug the value you're actually reading from the Stream and testing for in your if statement on line 37 with:
Serial.println("Reading: " + Serial.read());
Hope it helps.
-Cheers

RTMP_Write function use

I'm trying to use the librtmp library and it worked pretty well to pull a stream. But now I am trying to publish a stream and for that I believe I have to use the RTMP_Write function.
What I am trying to accomplish here is a simple c++ program that will read from a file and try to push the stream to a crtmp server. The connection and stream creation is ok, but I'm quite puzzled by the use of RTMP_Write.
Here is what I did:
int Upload(RTMP * rtmp, FILE * file){
int nRead = 0;
unsigned int nWrite = 0;
int diff = 0;
int bufferSize = 64 * 1024;
int byteSum = 0;
int count = 0;
char * buffer;
buffer = (char *) malloc(bufferSize);
do{
nRead = fread(buffer+diff,1,bufferSize-diff,file);
if(nRead != bufferSize){
if(feof(file)){
RTMP_LogPrintf("End of file reached!\n");
break;
}else if(ferror(file)){
RTMP_LogPrintf("Error reading from file stream detected\n");
break;
}
}
count += 1;
byteSum += nRead;
RTMP_LogPrintf("Read %d from file, Sum: %d, Count: %d\n",nRead,byteSum,count);
nWrite = RTMP_Write(rtmp,buffer,nRead);
if(nWrite != nRead){
diff = nRead - nWrite;
memcpy(buffer,(const void*)(buffer+bufferSize-diff),diff);
}
}while(!RTMP_ctrlC && RTMP_IsConnected(rtmp) && !RTMP_IsTimedout(rtmp));
free(buffer);
return RD_SUCCESS;
}
In this Upload function I am receiving the already initiallized RTMP structure and a pointer to an open file.
This actually works and I can see some video being displayed, but it soon gets lost and stops sending packages. I managed to understand that it happens whenever the buffer that I setup (and which I randomly required to be 64k, no special reason for that) happens to split the flv tag (http://osflash.org/flv#flv_format) of a new package.
For that I modified the RTMP_Write function and told it to verify if it will be able to decode the whole flv tag (packet type, body size, timestamp, etc..) and if it will not, then it should just return the amount of useful bytes left in the buffer.
if(s2 - 11 <= 0){
rest = size - s2;
return rest;
}
The code above takes notice of this, and if the value returned by RTMP_Write is not the amount of bytes it was supposed to send, then it knows that value is the amount of useful bytes left in the buffer. I then copy these bytes to the beginning of the buffer and read more from the file.
But I keep getting problems with it, so I was wondering: what is the correct use of this function anyway? is there a specific buffer value that I should be using? (don't think so) or is it buggy by itself?

Fade in multiple LEDs with Arduino

I need to figure out how to fade in and out of multiple LEDS in a function with an Arduino. Can't use delay() because other things need to run while the light is fading. This is what it has so far, but does not work.
int value = 0; // variable to keep the actual value
int ledpin = 9; // light connected to digital pin 9
int p1 = 0;
void setup()
{
// nothing for setup
Serial.begin(9600);
}
void loop()
{
inout(50, 30, 9, 0, 0);
//inout(20, 20, 10);
}
void inout(int inDelay, int outDelay, int ledpin, long previousmil, int done)
{
if(millis() - previousmil>inDelay){
if (value <=255){
analogWrite(ledpin, value); // sets the value (range from 0 to 255)
value+=5;
}
previousmil=millis();
}
if(value = 260)
done = 1;
if(millis() - previousmil>outDelay && done == 1){
if (value >0){
analogWrite(ledpin, value); // sets the value (range from 0 to 255)
value-=5;
}
previousmil=millis();
}
}
The only obvious thing is that you've got a state flag for which way to increment value, but you're not testing it in your first if. It would be better to structure your code a bit more. You also may want to track more than one value if you have more than one pin, unless they all should fade in and out at the same time. In that case you'd be best off with an array of structs with the parameters for each pine.
One way of using delay with multiple tasks is to have each task work on the time elapsed since the last loop, and adjust the delay at the end of your loop for the time the tasks take. If your loop is something like:
static unsigned long last_time = 0; // set to millis() in setup
static unsigned long refresh_period = 20; // 50Hz
void loop()
{
unsigned long time = millis();
unsigned long delta = time - last_time;
doTask1( delta );
doTask2( delta );
doTask3( delta );
doTask4( delta );
// as tasks may have taken some millis, adjust delay
unsigned long post_time = millis();
if ( post_time - last_time < refresh_period )
delay( refresh_period - ( post_time - last_time ) );
last_time = time;
}
Then each task will be run about once every 20ms, and will be passed 20 or so as the number of milliseconds to update their state for. So you get some delay, but everything has a chance to update.
Speculating, but this seems wrong:
if(value=260)
(reminding me of the worlds last mistake in C)
If you want to throw hardware at the problem, you can hook up your LEDs to an external controller chip, like the TI TLC5940. Those let you program a brightness level per LED and handle the PWM output to the LEDs separately from the ATMega CPU in the Arduino. You only need to reprogram the TLC chip when you want the brightness level to change. There's a nice TLC library available to handle communication with the chip on Google Code.