×
Samples Blogs Make Payment About Us Reviews 4.9/5 Order Now

Implementing a Circular Linked List with Function Pointers for Round-Robin Scheduling

September 09, 2024
Andrew Reisinger
Andrew Reisinger
🇺🇸 United States
C
Andrew Reisinger is a seasoned C Programming Assignment Expert with over a decade of experience. Specializing in data structures, algorithms, and embedded systems, he helps students and professionals tackle complex C programming challenges. John is known for his clear explanations, strong problem-solving skills, and dedication to student success.

Claim Your Discount Today

Take your coding game to new heights with expert help at unbeatable prices. Got a tricky project or a tight deadline? We’ve got you covered! Use code PHHBF10 at checkout and save BIG. Don’t wait—this exclusive Black Friday deal won’t last long. Secure your academic success today!

Black Friday Alert! Unlock a 10% Discount on All Assignments
Use Code PHHBF10

We Accept

Tip of the day
When working on Erlang assignments, focus on mastering the use of lightweight processes and concurrency. Also, take advantage of pattern matching and immutability to simplify debugging and enhance code reliability.
News
In 2024, updates to Python libraries like PyTorch and web frameworks like Django are transforming programming education, making machine learning and web development more accessible for students.
Key Topics
  • Setting Up the Project
    • Creating the Eclipse Project
    • Setting Up the Simulation Server
  • Implementing the Round-Robin Scheduler
    • Defining Function Pointers and Linked List Structure
    • Creating Task Prototypes
    • Main Function
  • Implementing System Tasks
    • Task 1: Sensor / Temperature Data
    • Task 2: Button Press Detection
    • Task 3: Set Mode
  • Filtering and Displaying Data
    • Task 4: Filter Mode
    • Task 5: Display Update
    • Task 6: Check Exit Condition
  • Testing and Debugging
    • Testing Individual Tasks
    • Integrating and Testing All Tasks
  • Debugging Common Issues
    • 1. Socket Connection Issues:
    • 2. Task Synchronization Problems:
    • 3. Unexpected Task Behavior:
  • Conclusion

In this blog post, we will walk through the implementation of a circular linked list in C, which holds function pointers to manage tasks for a body thermometer system. This project is divided into two main activities: creating the program shell and implementing the full system functionality. If you're seeking help with C Assignment, this guide will be particularly beneficial. We'll cover the setup, coding, and testing processes necessary to complete these activities.

Setting Up the Project

Before diving into the code, it's essential to set up the project environment correctly. This section covers the initial setup steps, creating the project in Eclipse, and preparing the simulation server.

Creating the Eclipse Project

To begin, you need to create a new project in Eclipse.

1. Starting a New Project:

Building-a-Round-Robin-Scheduler
  • Open Eclipse.
  • Navigate to File -> New -> C/C++ Project.
  • Select C Managed Build and name the project M6Lab.
  • Choose Hello World ANSI C Project and Cross GCC.

2. Project Configuration:

  • Once the project is created, replace the default main.c file with our starter code.
  • Add the necessary header files for socket communication:

#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <stdint.h>

Setting Up the Simulation Server

The simulation server runs on your host platform and provides simulated register and temperature values.

1. Creating the Simulation Server Project:

  • Start a new project in Eclipse: File -> New -> C/C++ Project.
  • Select C Managed Build and name the project SimulationServer.
  • Choose Hello World ANSI C Project and Linux GCC.

2. Configuring the Simulation Server:

  • Replace the default source file with SimulationServer.c.
  • Modify the IP addresses in the TempServer and RegTemp functions to match your server's IP.
  • Change the build configuration to Release.
  • Add -pthread to the linker options under project properties.

Implementing the Round-Robin Scheduler

With the project setup complete, we move on to implementing the round-robin scheduler using a circular linked list. This section includes the definition of function pointers, the structure of the linked list, and the main loop.

Defining Function Pointers and Linked List Structure

First, we define a generic function pointer and the structure for our linked list nodes.

typedef void* (*FunctionPointer)(double *, int *, char *, char *);

typedef void* (*FunctionPointer)(double *, int *, char *, char *); typedef struct fcnNode { FunctionPointer fcnPtr; struct fcnNode *nextNode; } fcnNode;

Creating Task Prototypes

Next, we declare prototypes for each of our six system tasks.

void * T1(double *, int *, char *, char *); void * T2(double *, int *, char *, char *); void * T3(double *, int *, char *, char *); void * T4(double *, int *, char *, char *); void * T5(double *, int *, char *, char *); void * T6(double *, int *, char *, char *);

Main Function

The main function initializes shared resources, creates the circular linked list, and starts the round-robin loop.

int main() { double currentTemp = 0; int exitLoop = 0; char tempVal = (char)0x00; char regVal = (char)0x00; fcnNode *headerNode = malloc(sizeof(fcnNode)); fcnNode *currentNode = headerNode; currentNode->fcnPtr = &T1; currentNode->nextNode = malloc(sizeof(fcnNode)); currentNode = currentNode->nextNode; currentNode->fcnPtr = &T2; currentNode->nextNode = malloc(sizeof(fcnNode)); currentNode = currentNode->nextNode; currentNode->fcnPtr = &T3; currentNode->nextNode = malloc(sizeof(fcnNode)); currentNode = currentNode->nextNode; currentNode->fcnPtr = &T4; currentNode->nextNode = malloc(sizeof(fcnNode)); currentNode = currentNode->nextNode; currentNode->fcnPtr = &T5; currentNode->nextNode = malloc(sizeof(fcnNode)); currentNode = currentNode->nextNode; currentNode->fcnPtr = &T6; currentNode->nextNode = headerNode; currentNode = headerNode; while (!exitLoop) { FunctionPointer fun = currentNode->fcnPtr; fun(&currentTemp, &exitLoop, &tempVal, &regVal); currentNode = currentNode->nextNode; } printf("Goodbye!\n"); return 0; }

Implementing System Tasks

This section details the implementation of each system task, including sensor data handling, button presses, mode filtering, and LCD updates.

Task 1: Sensor / Temperature Data

Task 1 reads the SSR and SDR registers from the simulation server.

void * T1(double *currentTemp, int *exitLoop, char *tempVal, char *regVal) { int socketfd, len, result, BUF_SIZE = 1; struct sockaddr_in address; char buffer; socketfd = socket(AF_INET, SOCK_STREAM, 0); if (socketfd == -1) { printf("socket creation failed...\n"); exit(0); } bzero(&address, sizeof(address)); address.sin_family = AF_INET; address.sin_addr.s_addr = inet_addr("127.0.0.1"); // Update with actual server IP address.sin_port = htons(5000); result = connect(socketfd, (struct sockaddr *)&address, sizeof(address)); if (result == -1) { printf("connection to server failed...\n"); close(socketfd); return NULL; } // Read SSR len = write(socketfd, "READSSR", BUF_SIZE); len = read(socketfd, &buffer, BUF_SIZE); *regVal = buffer; // Read SDR len = write(socketfd, "READSDR", BUF_SIZE); len = read(socketfd, &buffer, BUF_SIZE); *tempVal = buffer; close(socketfd); return NULL; }

Task 2: Button Press Detection

Task 2 detects button presses by checking the register values read by Task 1.

Task 2 detects button presses by checking the register values read by Task 1. void * T2(double *currentTemp, int *exitLoop, char *tempVal, char *regVal) { if (*regVal & 0x01) { printf("Button Press Detected!\n"); } return NULL; }

Task 3: Set Mode

Task 3 sets the mode based on the button press detected by Task 2.

void * T3(double *currentTemp, int *exitLoop, char *tempVal, char *regVal) { static int mode = 0; if (*regVal & 0x01) { mode = (mode + 1) % 3; // Cycle through modes 0, 1, 2 printf("Mode changed to %d\n", mode); } return NULL; }

Filtering and Displaying Data

This section discusses filtering temperature data and updating the LCD display.

Task 4: Filter Mode

Task 4 applies a filter based on the current mode to the temperature value read by Task 1.

void * T4(double *currentTemp, int *exitLoop, char *tempVal, char *regVal) { static double lastTemp = 0; static int mode = 0; if (mode == 0) { *currentTemp = *tempVal; // No filter } else if (mode == 1) { *currentTemp = (lastTemp + *tempVal) / 2; // Simple average } else if (mode == 2) { *currentTemp = 0.8 * lastTemp + 0.2 * *tempVal; // Exponential smoothing } lastTemp = *currentTemp; printf("Filtered Temperature: %.2f\n", *currentTemp); return NULL; }

Task 5: Display Update

Task 5 updates the LCD display with the current temperature value.

void * T5(double *currentTemp, int *exitLoop, char *tempVal, char *regVal) { printf("Updating Display: %.2f\n", *currentTemp); // Code to update the LCD would go here return NULL; }

Task 6: Check Exit Condition

Task 6 checks if the exit condition is met, allowing the program to terminate gracefully.

void * T6(double *currentTemp, int *exitLoop, char *tempVal, char *regVal) { static int counter = 0; counter++; if (counter >= 100) { *exitLoop = 1; } return NULL; }

Testing and Debugging

In this section, we cover the procedures for testing and debugging the system to ensure it functions correctly.

Testing Individual Tasks

Testing each task individually is crucial to verify its functionality.

Task 1: Sensor / Temperature Data

Test Task 1 by running the simulation server and checking if the program reads the SSR and SDR registers correctly.

int main() { double currentTemp = 0; int exitLoop = 0; char tempVal = (char)0x00; char regVal = (char)0x00; T1(&currentTemp, &exitLoop, &tempVal, &regVal); printf("Temperature Value: %d, Register Value: %d\n", tempVal, regVal); return 0; }

Task 2: Button Press Detection

Simulate button presses by setting the regVal manually and check if Task 2 detects them.

int main() { double currentTemp = 0; int exitLoop = 0; char tempVal = (char)0x00; char regVal = (char)0x01; // Simulate button press T2(&currentTemp, &exitLoop, &tempVal, &regVal); return 0; }

Task 3: Set Mode

Check if Task 3 changes the mode correctly when a button press is detected.

int main() { double currentTemp = 0; int exitLoop = 0; char tempVal = (char)0x00; char regVal = (char)0x01; // Simulate button press T3(&currentTemp, &exitLoop, &tempVal, &regVal); return 0; }

Integrating and Testing All Tasks

After testing individual tasks, integrate them into the main program and test the complete system.

int main() { double currentTemp = 0; int exitLoop = 0; char tempVal = (char)0x00; char regVal = (char)0x00; fcnNode *headerNode = malloc(sizeof(fcnNode)); fcnNode *currentNode = headerNode; currentNode->fcnPtr = &T1; currentNode->nextNode = malloc(sizeof(fcnNode)); currentNode = currentNode->nextNode; currentNode->fcnPtr = &T2; currentNode->nextNode = malloc(sizeof(fcnNode)); currentNode = currentNode->nextNode; currentNode->fcnPtr = &T3; currentNode->nextNode = malloc(sizeof(fcnNode)); currentNode = currentNode->nextNode; currentNode->fcnPtr = &T4; currentNode->nextNode = malloc(sizeof(fcnNode)); currentNode = currentNode->nextNode; currentNode->fcnPtr = &T5; currentNode->nextNode = malloc(sizeof(fcnNode)); currentNode = currentNode->nextNode; currentNode->fcnPtr = &T6; currentNode->nextNode = headerNode; currentNode = headerNode; while (!exitLoop) { FunctionPointer fun = currentNode->fcnPtr; fun(&currentTemp, &exitLoop, &tempVal, &regVal); currentNode = currentNode->nextNode; } printf("Goodbye!\n"); return 0; }

Debugging Common Issues

When integrating and testing the system, you may encounter common issues such as incorrect socket connections, task synchronization problems, or unexpected task behavior.

1. Socket Connection Issues:

  • Ensure the simulation server is running and listening on the correct IP and port.
  • Check firewall settings that may block socket connections.

2. Task Synchronization Problems:

  • Use printf statements to trace task execution order and timing.
  • Ensure shared variables are accessed correctly without race conditions.

3. Unexpected Task Behavior:

  • Verify task logic and ensure they operate on correct data values.
  • Test tasks with different input scenarios to cover edge cases.

Conclusion

Implementing a circular linked list with function pointers for a round-robin scheduler in C provides a robust framework for managing multiple tasks in a body thermometer system. By carefully setting up the project, defining the task functions, and testing each component, we can build a reliable and efficient scheduling system. This approach can be extended to other embedded systems and real-time applications, demonstrating the flexibility and power of function pointers and circular linked lists in programming assignment.

Similar Blogs