Create an array at different memory locations for each loop - c++

Good morning everyone,
I am currently working on a data acquisition project, where I have to read sensors (at around 10 kHz) and transmit the data via Wi-Fi and the MQTT-protocol. I am using an ESP32 for both of these tasks.
One core is doing the sensor reading and the other core does the transmitting stuff. I also use the FreeRTOS for this.
Now, I want to pass the data as efficient as possible between the task. Currently I'm using the xQueue function built in the FreeRtos. I pass pointers in the Queue which point to an array, where one datapackage is stored.
Task one:
*sensor reading*
for(xx)
{
data_array[x] = sensor_data;
}
if {packageSize == 120}
{
xQueueSend(Queue1, &data_pointer, 0);
}
________________________
Task two:
if( uxQueueMessagesWaiting(Queue1) >= 1)
{
xQueueReceive(Queue1, &received_pointer, 0);
memcpy(data_send, received_pointer, packageSize);
* MQTT-Client sending data_send *
}
You see, my problem isn't the creation of the array with different pointers. The sensor reading task needs to create an array for every package, without overwritting the previous one.
My initial idea was to use the new and delete combination but it gave me strange results.
Is there any way I can change the location of the array on the memory at every loop of task one?
EDIT:
/* general variables*/
const int len = 150;
uint8_t data_received[len];
uint8_t data_send[len];
uint8_t *queue_pointer = 0;
uint8_t *received_pointer = 0;
uint8_t *to_delete_pointer = 0;
uint8_t dummy_data = 0;
int v = 0;
/* multithreading variables */
TaskHandle_t SPI_COM;
TaskHandle_t WIFI;
QueueHandle_t buffer_daten;
/* --------------------- Fake-SPI-Kommunikation auf Core 1 -------------------- */
void SPI_COM_code(void *pvParameters)
{
for (;;)
{
while (v <= 10000)
{
//queue_pointer = new int[len]; // creates a new array
queue_pointer = data_received;
queue_pointer[dummy_data] = dummy_data;
dummy_data++;
delayMicroseconds(100); // Dummy-Interrupt
if (dummy_data == len - 1)
{
dummy_data = 0;
xQueueSend(buffer_daten, &queue_pointer, 0);
v++;
}
}
}
}
/* --------------------- WiFi-Übertragung auf Core 0 --------------------- */
void WIFI_code(void *pvParameters)
{
for (;;)
{
//MQTT_connect();
if (uxQueueMessagesWaiting(buffer_daten) > 0)
{
xQueueReceive(buffer_daten, &received_pointer, 0);
to_delete_pointer = received_pointer;
memcpy(data_send, received_pointer, len);
// Data gets published by MQTT-Client
delayMicroseconds(12);
//delete[] to_delete_pointer; // deletes array, which was send
}
}
}
/* ----------------------------------- Setup ---------------------------------- */
void setup()
{
disableCore0WDT(); // <----- MÖGLICHE PROBLEMQUELLE
Serial.begin(115200);
buffer_daten = xQueueCreate(1000, sizeof(int));
xTaskCreatePinnedToCore(
SPI_COM_code, /* Task function. */
"SPI_COM", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&SPI_COM, /* Task handle to keep track of created task */
1); /* pin task to core 0 */
delay(500);
xTaskCreatePinnedToCore(
WIFI_code, /* Task function. */
"WIFI", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
2, /* priority of the task */
&WIFI, /* Task handle to keep track of created task */
0); /* pin task to core 1 */
delay(500);
}
void loop()
{
}

I would suggest you use a RTOS Message Buffers for this task
With this functions you could copy your array into the buffer and the second task could get it, when the data is available.
In both cases the consumer task should use the timeout '0' to request the data.
If the MQTT task is faster than the data acquisition (and it should be or your buffers will overflow sooner or later) this will lead to invalid pointers:
xQueueReceive(buffer_daten, &received_pointer, 0);
If the is no data available the function will return immediately giving you an invalid received_pointer.
You should either check the return value of xQueueReceive or set the timeout to portMAX_DELAY.

Related

Use variables with both cores and tasks ESP32

Im trying to read data from an i2c device, which is recieved by core 0, then that data is stored into some global values, and then those values are readed by the core 1, and then printed out. The problem is whenever the core 0 tries to access those variables, it outputs "guru meditation error core 0 panic'ed (loadprohibited). exception was unhandled". What is the way in which the 2 cores can communicate to one another?
TaskHandle_t Task1;
TaskHandle_t Task2;
#include <Adafruit_ADS1X15.h>
Adafruit_ADS1015 ads;
volatile int16_t adc0, adc1, adc2, adc3;
volatile float volts0, volts1, volts2, volts3;
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("Hello!");
Serial.println("Getting single-ended readings from AIN0..3");
Serial.println("ADC Range: +/- 6.144V (1 bit = 3mV/ADS1015, 0.1875mV/ADS1115");
//create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
xTaskCreatePinnedToCore(
Task1code, /* Task function. */
"Task1", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
delay(500);
//create a task that will be executed in the Task2code() function, with priority 1 and executed on core 1
xTaskCreatePinnedToCore(
Task2code, /* Task function. */
"Task2", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
2, /* priority of the task */
&Task2, /* Task handle to keep track of created task */
1); /* pin task to core 1 */
delay(500);
if (!ads.begin()) {
Serial.println("Failed to initialize ADS.");
while (1);
}
}
void Task1code( void * pvParameters ){
for(;;){
Serial.print("Task1 running on core ");
Serial.println(xPortGetCoreID());
adc0 = ads.readADC_SingleEnded(0);
adc1 = ads.readADC_SingleEnded(1);
adc2 = ads.readADC_SingleEnded(2);
adc3 = ads.readADC_SingleEnded(3);
volts0 = ads.computeVolts(adc0);
volts1 = ads.computeVolts(adc1);
volts2 = ads.computeVolts(adc2);
volts3 = ads.computeVolts(adc3);
delay(100);
}
}
void Task2code( void * pvParameters ){
delay(500);
Serial.print("Task2 running on core ");
Serial.println(xPortGetCoreID());
for(;;){}{
Serial.println("-----------------------------------------------------------");
Serial.print("AIN0: "); Serial.print(adc0); Serial.print(" "); Serial.print(volts0); Serial.println("V");
Serial.print("AIN1: "); Serial.print(adc1); Serial.print(" "); Serial.print(volts1); Serial.println("V");
Serial.print("AIN2: "); Serial.print(adc2); Serial.print(" "); Serial.print(volts2); Serial.println("V");
Serial.print("AIN3: "); Serial.print(adc3); Serial.print(" "); Serial.print(volts3); Serial.println("V");
delay(100);
}
}
void loop() {
}
You can create a semaphore and take it when try to access the variable. If you done accessing it, you can give it back. When you take a semaphore, other code blocks will wait for the other to give it back. You can configure the time it should wait for a given semaphore. Here is a (link) explaining in more details.
Here is an example:
SemaphoreHandle_t i2cSemaphore;
void createSemaphore(){
i2cSemaphore = xSemaphoreCreateMutex();
xSemaphoreGive( ( i2cSemaphore) );
}
// Lock the variable indefinietly. ( wait for it to be accessible )
void lockVariable(){
xSemaphoreTake(i2cSemaphore, portMAX_DELAY);
}
// give back the semaphore.
void unlockVariable(){
xSemaphoreGive(i2cSemaphore);
}
TaskHandle_t Task1;
TaskHandle_t Task2;
#include <Adafruit_ADS1X15.h>
Adafruit_ADS1015 ads;
volatile int16_t adc0, adc1, adc2, adc3;
volatile float volts0, volts1, volts2, volts3;
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("Hello!");
Serial.println("Getting single-ended readings from AIN0..3");
Serial.println("ADC Range: +/- 6.144V (1 bit = 3mV/ADS1015, 0.1875mV/ADS1115");
createSemaphore();
//create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
xTaskCreatePinnedToCore(
Task1code, /* Task function. */
"Task1", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
delay(500);
//create a task that will be executed in the Task2code() function, with priority 1 and executed on core 1
xTaskCreatePinnedToCore(
Task2code, /* Task function. */
"Task2", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
2, /* priority of the task */
&Task2, /* Task handle to keep track of created task */
1); /* pin task to core 1 */
delay(500);
if (!ads.begin()) {
Serial.println("Failed to initialize ADS.");
while (1);
}
}
void Task1code( void * pvParameters ){
for(;;){
lockVariable();
Serial.print("Task1 running on core ");
Serial.println(xPortGetCoreID());
adc0 = ads.readADC_SingleEnded(0);
adc1 = ads.readADC_SingleEnded(1);
adc2 = ads.readADC_SingleEnded(2);
adc3 = ads.readADC_SingleEnded(3);
volts0 = ads.computeVolts(adc0);
volts1 = ads.computeVolts(adc1);
volts2 = ads.computeVolts(adc2);
volts3 = ads.computeVolts(adc3);
unlockVariable();
vTaskDelay(100);
}
}
void Task2code( void * pvParameters ){
delay(500);
Serial.print("Task2 running on core ");
Serial.println(xPortGetCoreID());
for(;;){}{
lockVariable();
Serial.println("-----------------------------------------------------------");
Serial.print("AIN0: "); Serial.print(adc0); Serial.print(" "); Serial.print(volts0); Serial.println("V");
Serial.print("AIN1: "); Serial.print(adc1); Serial.print(" "); Serial.print(volts1); Serial.println("V");
Serial.print("AIN2: "); Serial.print(adc2); Serial.print(" "); Serial.print(volts2); Serial.println("V");
Serial.print("AIN3: "); Serial.print(adc3); Serial.print(" "); Serial.print(volts3); Serial.println("V");
unlockVariable();
vTaskDelay(100);
}
}
void loop() {
}

FreeRTOS: an approach to delay a member function inside a list, without blocking the iteration of the list

I want to create a function with a delay for each instance of a class. If some condition occur a task will be created and a delay will happen only to this instance.
/* Task to be created. */
void vTaskCode( void * pvParameters ){
const TickType_t xDelay = 1000 / portTICK_PERIOD_MS;
//Do some logic...
vTaskDelay(xDelay);
//indicate the task has finished
configASSERT(1);
}
BaseType_t xReturned;
TaskHandle_t xHandle = NULL;
class foo {
void afunc(){
//Create a task of vTaskCode if it doesnt exist
if (xHandle == NULL){
xReturned = xTaskCreate(
vTaskCode, /* Function that implements the task. */
"Auxiliary", /* Text name for the task. */
STACK_SIZE, /* Stack size in words, not bytes. */
NULL, /* Parameter passed into the task. */
tskIDLE_PRIORITY,/* Priority at which the task is created. */
&xHandle );
}}
//Should be called after the task is complete.
if( xReturned == pdPASS )
{
vTaskDelete( xHandle );
}
}
//main loop
void MainLOOP( void * pvParameters ){
for (;;){
const TickType_t xDelay = 5 / portTICK_PERIOD_MS;
for (std::list<foo>::iterator itr = foolist.begin(); itr != foolist.end(); ++itr)
{
itr->afunc();
}
}}
void setup(){
std::list<foo> foolist;
///...SOME CODE TO POPULATE FOOLIST
xTaskCreate(
MainLOOP, /* Function that implements the task. */
"MAIN", /* Text name for the task. */
STACK_SIZE, /* Stack size in words, not bytes. */
NULL, /* Parameter passed into the task. */
tskIDLE_PRIORITY,/* Priority at which the task is created. */
NULL);
}
Will each delay work? Or at each iteration a new task will run? Will the for loop be blocked so each iteration stops or it will work async?
The whole idea is to avoid using millis() function and not blocking each iteraction of the list.
Another restrain is speed as this loop work at 5ms and i would like to use the core 0.
EDIT: #HS2 raised that a better approach should be using a FreeRTOS timer
As HS2 have said, dynamically create tasks is not a good aproach. Using FreeRTOS timers does not work well if your timed action has to run many functions and objects because of the timer queue.
The solution was to make a task for each object inside the list, instead a major task for the list:
TASK of each object of the list
void Djtri::analisa(void *pvParameters) {
//Serial.printf("\n ABT: %x FCH: %x BI: %x", totAbt, totFch, *bi);
Djtri *djpnt = (Djtri*) pvParameters;
const TickType_t tmpAb = djpnt->tmpAbt / portTICK_PERIOD_MS;
const TickType_t tmpFc = djpnt->tmpFch / portTICK_PERIOD_MS;
const TickType_t looptime = 5 / portTICK_PERIOD_MS;
for (;;){
if ((djpnt->biAbt & io[0]) && (djpnt->estado != ABERTO)) {
Serial.printf("\nOrdem de abertura do DJ %X ", djpnt->id);
vTaskDelay(tmpAb);
djpnt->abrir();
} else if ((djpnt->biFch & io[0]) && (djpnt->estado != FECHADO)) {
Serial.printf("\nOrdem de fechamento do DJ %X", djpnt->id);
vTaskDelay(tmpFc);
djpnt->fechar();
}
vTaskDelay(looptime);
}
}
Create a task for each item on setup of ESP32
for (auto itr = djtrilst.begin(); itr != djtrilst.end(); ++itr){
Serial.printf("\n Criando task para DJ tri: %x", itr->id);
xTaskCreatePinnedToCore(
Djtri::analisa, /* Function to implement the task */
"Djtri", /* Name of the task */
8000, /* Stack size in words */
(void*) &*itr, /* Task input parameter */
0, /* Priority of the task */
nullptr, /* Task handle. */
0); /* Core where the task should run */
}
Observe that I used the task input parameter to pass the pointer of the object, as a task function must be static.

Problem with FULLY_CONNECTED op in TF Lite

I'd like to run a simple neural network model which uses Keras on a Rasperry microcontroller. I get a problem when I use a layer. The code is defined like this:
#include "main.h"
#include <string.h>
#include "tensorflow/lite/micro/kernels/micro_ops.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/version.h"
#include "my_model.h"
/* Private variables
TIM_HandleTypeDef htim16;
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
// TFLite globals
namespace {
tflite::ErrorReporter* error_reporter = nullptr;
const tflite::Model* model = nullptr;
tflite::MicroInterpreter* interpreter = nullptr;
TfLiteTensor* model_input = nullptr;
TfLiteTensor* model_output = nullptr;
// Create an area of memory to use for input, output, and other TensorFlow
// arrays. You'll need to adjust this by compiling, running, and looking
// for errors.
constexpr int kTensorArenaSize = 2 * 1024;
__attribute__((aligned(16)))uint8_t tensor_arena[kTensorArenaSize];
} // namespace
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_TIM16_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code
/* USER CODE BEGIN 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
char buf[50];
int buf_len = 0;
TfLiteStatus tflite_status;
uint32_t num_elements;
uint32_t timestamp;
float y_val;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_TIM16_Init();
/* USER CODE BEGIN 2 */
// Start timer/counter
HAL_TIM_Base_Start(&htim16);
// Set up logging (modify tensorflow/lite/micro/debug_log.cc)
static tflite::MicroErrorReporter micro_error_reporter;
error_reporter = &micro_error_reporter;
// Say something to test error reporter
error_reporter->Report("STM32 TensorFlow Lite test");
// Map the model into a usable data structure
model = tflite::GetModel(my_model);
if (model->version() != TFLITE_SCHEMA_VERSION)
{
error_reporter->Report("Model version does not match Schema");
while(1);
}
// Pull in only needed operations (should match NN layers). Template parameter
// <n> is number of ops to be added. Available ops:
// tensorflow/lite/micro/kernels/micro_ops.h
static tflite::MicroMutableOpResolver<1> micro_op_resolver;
// Add dense neural network layer operation
tflite_status = micro_op_resolver.AddBuiltin(
tflite::BuiltinOperator_FULLY_CONNECTED,
tflite::ops::micro::Register_FULLY_CONNECTED());
if (tflite_status != kTfLiteOk)
{
error_reporter->Report("Could not add FULLY CONNECTED op");
while(1);
}
// Build an interpreter to run the model with.
static tflite::MicroInterpreter static_interpreter(
model, micro_op_resolver, tensor_arena, kTensorArenaSize, error_reporter);
interpreter = &static_interpreter;
// Allocate memory from the tensor_arena for the model's tensors.
tflite_status = interpreter->AllocateTensors();
if (tflite_status != kTfLiteOk)
{
error_reporter->Report("AllocateTensors() failed");
while(1);
}
// Assign model input and output buffers (tensors) to pointers
model_input = interpreter->input(0);
model_output = interpreter->output(0);
// Get number of elements in input tensor
num_elements = model_input->bytes / sizeof(float);
buf_len = sprintf(buf, "Number of input elements: %lu\r\n", num_elements);
HAL_UART_Transmit(&huart2, (uint8_t *)buf, buf_len, 100);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// Fill input buffer (use test value)
for (uint32_t i = 0; i < num_elements; i++)
{
model_input->data.f[i] = 2.0f;
}
// Get current timestamp
timestamp = htim16.Instance->CNT;
// Run inference
tflite_status = interpreter->Invoke();
if (tflite_status != kTfLiteOk)
{
error_reporter->Report("Invoke failed");
}
// Read output (predicted y) of neural network
y_val = model_output->data.f[0];
// Print output of neural network along with inference time (microseconds)
buf_len = sprintf(buf,
"Output: %f | Duration: %lu\r\n",
y_val,
htim16.Instance->CNT - timestamp);
HAL_UART_Transmit(&huart2, (uint8_t *)buf, buf_len, 100);
// Wait before doing it again
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
When I run the program I got this compilation problem:
../Core/Src/main.cpp: In function 'int main()':
../Core/Src/main.cpp:181:57: error: no matching function for call to 'tflite::MicroMutableOpResolver<1>::AddBuiltin(tflite::BuiltinOperator, TfLiteRegistration*)'
tflite::ops::micro::Register_FULLY_CONNECTED());
^
In file included from ../Core/Src/main.cpp:31:0:
STM32CubeIDE/workspace_1.3.0/sine/tensorflow_lite/tensorflow/lite/micro/micro_mutable_op_resolver.h:470:16: note: candidate: TfLiteStatus tflite::MicroMutableOpResolver<tOpCount>::AddBuiltin(tflite::BuiltinOperator, const TfLiteRegistration&, tflite::MicroOpResolver::BuiltinParseFunction) [with unsigned int tOpCount = 1; TfLiteStatus = TfLiteStatus; TfLiteRegistration = TfLiteRegistration; tflite::MicroOpResolver::BuiltinParseFunction = TfLiteStatus (*)(const tflite::Operator*, tflite::BuiltinOperator, tflite::ErrorReporter*, tflite::BuiltinDataAllocator*, void**)]
TfLiteStatus AddBuiltin(tflite::BuiltinOperator op,
^~~~~~~~~~
STM32CubeIDE/workspace_1.3.0/sine/tensorflow_lite/tensorflow/lite/micro/micro_mutable_op_resolver.h:470:16: note: candidate expects 3 arguments, 2 provided
make: *** [Core/Src/subdir.mk:37: Core/Src/main.o] Error 1
"make -j2 all" terminated with exit code 2. Build might be incomplete.
I'm not sure which third parameter I have to insert for FULLY_CONNECTED() or if there is another problem.
I think I were running into a version mismatch between the TFlite for Micro Python library used to generate the model and the TFlite for Micro C/C++ library used to run inference. I solved the problem using this:
static tflite::MicroMutableOpResolver<1> micro_op_resolver;
tflite_status = micro_op_resolver.AddFullyConnected();
I had the same problem, man.
I want to transplant tflite to the development board of CEVA. There is no problem in compiling. In the process of running, there is also an error in AddBuiltin(full_connect).
At present, the only possible situation I guess is that some devices can not support tflite.
Did you check if the FULLY_CONNECTED operator is listed in the micro_ops.h header file? The header file contains a list of registration methods for a user to pick if their model requires the operator.
I had the same problem during compilation and discovered I was missing the method TfLiteRegistration Register_FULLY_CONNECTED() .

parsing complete messages from serial port

I am trying to read complete messages from my GPS via serial port.
The message I am looking for starts with:
0xB5 0x62 0x02 0x13
So I read from the serial port like so
while (running !=0)
{
int n = read (fd, input_buffer, sizeof input_buffer);
for (int i=0; i<BUFFER_SIZE; i++)
{
if (input_buffer[i]==0xB5 && input_buffer[i+1]== 0x62 && input_buffer[i+2]== 0x02 && input_buffer[i+3]== 0x13 && i<(BUFFER_SIZE-1) )
{
// process the message.
}
}
The problem I am having is that I need to get a complete message. Half of a message could be in the buffer one iteration. And the other half could come into the message the next iteration.
Somebody suggested that free the buffer up from the complete message. And then I move the rest of data in the buffer to the beginning of the buffer.
How do I do that or any other way that make sure I get every complete selected message that comes in?
edit//
I want a particular class and ID. But I can also read in the length
To minimize the overhead of making many read() syscalls of small byte counts, use an intermediate buffer in your code.
The read()s should be in blocking mode to avoid a return code of zero bytes.
#define BLEN 1024
unsigned char rbuf[BLEN];
unsigned char *rp = &rbuf[BLEN];
int bufcnt = 0;
static unsigned char getbyte(void)
{
if ((rp - rbuf) >= bufcnt) {
/* buffer needs refill */
bufcnt = read(fd, rbuf, BLEN);
if (bufcnt <= 0) {
/* report error, then abort */
}
rp = rbuf;
}
return *rp++;
}
For proper termios initialization code for the serial terminal, see this answer. You should increase the VMIN parameter to something closer to the BLEN value.
Now you can conveniently access the received data a byte at a time with minimal performance penalty.
#define MLEN 1024 /* choose appropriate value for message protocol */
unsigned char mesg[MLEN];
while (1) {
while (getbyte() != 0xB5)
/* hunt for 1st sync */ ;
retry_sync:
if ((sync = getbyte()) != 0x62) {
if (sync == 0xB5)
goto retry_sync;
else
continue; /* restart sync hunt */
}
class = getbyte();
id = getbyte();
length = getbyte();
length += getbyte() << 8;
if (length > MLEN) {
/* report error, then restart sync hunt */
continue;
}
for (i = 0; i < length; i++) {
mesg[i] = getbyte();
/* accumulate checksum */
}
chka = getbyte();
chkb = getbyte();
if ( /* valid checksum */ )
break; /* verified message */
/* report error, and restart sync hunt */
}
/* process the message */
switch (class) {
case 0x02:
if (id == 0x13) {
...
...
You can break the read into three parts. Find the start of a message. Then get the LENGTH. Then read the rest of the message.
// Should probably clear these in case data left over from a previous read
input_buffer[0] = input_buffer[1] = 0;
// First make sure first char is 0xB5
do {
n = read(fd, input_buffer, 1);
} while (0xB5 != input_buffer[0]);
// Check for 2nd sync char
n = read(fd, &input_buffer[1], 1);
if (input_buffer[1] != 0x62) {
// Error
return;
}
// Read up to LENGTH
n = read(fd, &input_buffer[2], 4);
// Parse length
//int length = *((int *)&input_buffer[4]);
// Since I don't know what size an int is on your system, this way is better
int length = input_buffer[4] | (input_buffer[5] << 8);
// Read rest of message
n = read(fd, &input_buffer[6], length);
// input_buffer should now have a complete message
You should add error checking...

In C, can't change a struct attribute except using #define val

In Minix 3.1.2a I've a struct "struct proc" where the PCB of any process stored,
but I've a problem when adding new attribute "p_currenthash" in the code below to this struct. I can't change its value except using a constant defined by #define directive; otherwise, the system stops responding. For clarity here is the structure:
struct proc {
struct stackframe_s p_reg; /* process' registers saved in stack frame */
#if (CHIP == INTEL)
reg_t p_ldt_sel; /* selector in gdt with ldt base and limit */
struct segdesc_s p_ldt[2+NR_REMOTE_SEGS]; /* CS, DS and remote segments */
#endif
#if (CHIP == M68000)
/* M68000 specific registers and FPU details go here. */
#endif
proc_nr_t p_nr; /* number of this process (for fast access) */
struct priv *p_priv; /* system privileges structure */
short p_rts_flags; /* process is runnable only if zero */
short p_misc_flags; /* flags that do suspend the process */
char p_priority; /* current scheduling priority */
char p_max_priority; /* maximum scheduling priority */
char p_ticks_left; /* number of scheduling ticks left */
char p_quantum_size; /* quantum size in ticks */
struct mem_map p_memmap[NR_LOCAL_SEGS]; /* memory map (T, D, S) */
clock_t p_user_time; /* user time in ticks */
clock_t p_sys_time; /* sys time in ticks */
struct proc *p_nextready; /* pointer to next ready process */
struct proc *p_caller_q; /* head of list of procs wishing to send */
struct proc *p_q_link; /* link to next proc wishing to send */
message *p_messbuf; /* pointer to passed message buffer */
int p_getfrom_e; /* from whom does process want to receive? */
int p_sendto_e; /* to whom does process want to send? */
sigset_t p_pending; /* bit map for pending kernel signals */
char p_name[P_NAME_LEN]; /* name of the process, including \0 */
int p_endpoint; /* endpoint number, generation-aware */
#if DEBUG_SCHED_CHECK
int p_ready, p_found;
#endif
char p_currenthash; /* hash */
};
Now, suppose I want to set its value. Initially I use the constant defined below.
#define NONE -1
register struct proc *rp;
rp->p_currenthash=NONE;
That works fine, but this: rp->p_currenthash=0 ; will cause the program to stop responding.
Any suggestions will be appreciated
Here's the main initialization in main():
/* Start the ball rolling. */
struct boot_image *ip; /* boot image pointer */
register struct proc *rp; /* process pointer */
register struct priv *sp; /* privilege structure pointer */
register int i, s;
int hdrindex; /* index to array of a.out headers */
phys_clicks text_base;
vir_clicks text_clicks, data_clicks;
reg_t ktsb; /* kernel task stack base */
struct exec e_hdr; /* for a copy of an a.out header */
/* Initialize the interrupt controller. */
intr_init(1);
/* Clear the process table. Anounce each slot as empty and set up mappings
* for proc_addr() and proc_nr() macros. Do the same for the table with
* privilege structures for the system processes.
*/
for (rp = BEG_PROC_ADDR, i = -NR_TASKS; rp < END_PROC_ADDR; ++rp, ++i) {
rp->p_rts_flags = SLOT_FREE; /* initialize free slot */
rp->p_nr = i; /* proc number from ptr */
rp->p_currenthash=NONE;
rp->p_endpoint = _ENDPOINT(0, rp->p_nr); /* generation no. 0 */
(pproc_addr + NR_TASKS)[i] = rp; /* proc ptr from number */
}
for (sp = BEG_PRIV_ADDR, i = 0; sp < END_PRIV_ADDR; ++sp, ++i) {
sp->s_proc_nr = NONE; /* initialize as free */
sp->s_id = i; /* priv structure index */
ppriv_addr[i] = sp; /* priv ptr from number */
}
/* Set up proc table entries for processes in boot image. The stacks of the
* kernel tasks are initialized to an array in data space. The stacks
* of the servers have been added to the data segment by the monitor, so
* the stack pointer is set to the end of the data segment. All the
* processes are in low memory on the 8086. On the 386 only the kernel
* is in low memory, the rest is loaded in extended memory.
*/
/* Task stacks. */
ktsb = (reg_t) t_stack;
for (i=0; i < NR_BOOT_PROCS; ++i) {
ip = &image[i]; /* process' attributes */
rp = proc_addr(ip->proc_nr); /* get process pointer */
ip->endpoint = rp->p_endpoint; /* ipc endpoint */
rp->p_max_priority = ip->priority; /* max scheduling priority */
rp->p_priority = ip->priority; /* current priority */
rp->p_quantum_size = ip->quantum; /* quantum size in ticks */
rp->p_ticks_left = ip->quantum; /* current credit */
strncpy(rp->p_name, ip->proc_name, P_NAME_LEN); /* set process name */
(void) get_priv(rp, (ip->flags & SYS_PROC)); /* assign structure */
priv(rp)->s_flags = ip->flags; /* process flags */
priv(rp)->s_trap_mask = ip->trap_mask; /* allowed traps */
priv(rp)->s_call_mask = ip->call_mask; /* kernel call mask */
priv(rp)->s_ipc_to.chunk[0] = ip->ipc_to; /* restrict targets */
if (iskerneln(proc_nr(rp))) { /* part of the kernel? */
if (ip->stksize > 0) { /* HARDWARE stack size is 0 */
rp->p_priv->s_stack_guard = (reg_t *) ktsb;
*rp->p_priv->s_stack_guard = STACK_GUARD;
}
ktsb += ip->stksize; /* point to high end of stack */
rp->p_reg.sp = ktsb; /* this task's initial stack ptr */
text_base = kinfo.code_base >> CLICK_SHIFT;
/* processes that are in the kernel */
hdrindex = 0; /* all use the first a.out header */
} else {
hdrindex = 1 + i-NR_TASKS; /* servers, drivers, INIT */
}
/* The bootstrap loader created an array of the a.out headers at
* absolute address 'aout'. Get one element to e_hdr.
*/
phys_copy(aout + hdrindex * A_MINHDR, vir2phys(&e_hdr),
(phys_bytes) A_MINHDR);
/* Convert addresses to clicks and build process memory map */
text_base = e_hdr.a_syms >> CLICK_SHIFT;
text_clicks = (e_hdr.a_text + CLICK_SIZE-1) >> CLICK_SHIFT;
if (!(e_hdr.a_flags & A_SEP)) text_clicks = 0; /* common I&D */
data_clicks = (e_hdr.a_total + CLICK_SIZE-1) >> CLICK_SHIFT;
rp->p_memmap[T].mem_phys = text_base;
rp->p_memmap[T].mem_len = text_clicks;
rp->p_memmap[D].mem_phys = text_base + text_clicks;
rp->p_memmap[D].mem_len = data_clicks;
rp->p_memmap[S].mem_phys = text_base + text_clicks + data_clicks;
rp->p_memmap[S].mem_vir = data_clicks; /* empty - stack is in data */
/* Set initial register values. The processor status word for tasks
* is different from that of other processes because tasks can
* access I/O; this is not allowed to less-privileged processes
*/
rp->p_reg.pc = (reg_t) ip->initial_pc;
rp->p_reg.psw = (iskernelp(rp)) ? INIT_TASK_PSW : INIT_PSW;
/* Initialize the server stack pointer. Take it down one word
* to give crtso.s something to use as "argc".
*/
if (isusern(proc_nr(rp))) { /* user-space process? */
rp->p_reg.sp = (rp->p_memmap[S].mem_vir +
rp->p_memmap[S].mem_len) << CLICK_SHIFT;
rp->p_reg.sp -= sizeof(reg_t);
}
/* Set ready. The HARDWARE task is never ready. */
if (rp->p_nr != HARDWARE) {
rp->p_rts_flags = 0; /* runnable if no flags */
lock_enqueue(rp); /* add to scheduling queues */
} else {
rp->p_rts_flags = NO_MAP; /* prevent from running */
}
/* Code and data segments must be allocated in protected mode. */
alloc_segments(rp);
}
register struct proc *rp;
rp->p_currenthash=NONE;
rp is an uninitialized pointer; it isn't pointing to a valid struct proc object, and so dereferencing it leads to undefined behavior. The fact that this didn't crash when assigning -1 was pure luck. (bad luck, because it misled you to believe you were doing something meaningful)
acutually the problem not solved ,first the "p_currenthash" initialized in the main as shown above ,later in a function called pic_proc ,i've this code :
register struct proc **xpp; /* iterate over queue */
register struct proc *rp; /* process to run */
int q;
for (q=0; q < NR_SCHED_QUEUES; q++)
{
if ( (rp = rdy_head[q]) != NIL_PROC)
{
for (xpp = &rdy_head[q]; *xpp != NIL_PROC; xpp = &(*xpp)->p_nextready)
{
if ((*xpp)->p_currenthash==NONE)
{
pick_val++;
}
}
}
}
that code works fine ,no inside the if if i changed the attribute "p_currenthash" the problem ocuured as bellow:
register struct proc **xpp; /* iterate over queue */
register struct proc *rp; /* process to run */
int q;
for (q=0; q < NR_SCHED_QUEUES; q++)
{
if ( (rp = rdy_head[q]) != NIL_PROC)
{
for (xpp = &rdy_head[q]; *xpp != NIL_PROC; xpp = &(*xpp)->p_nextready)
{
if ((*xpp)->p_currenthash==NONE)
{
pick_val++;
(*xpp)->p_currenthash=1;
}
}
}
}
i really can't realize the problem.