Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added simulation project #256

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions projects/simulation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!--
General guidelines
These are just guidelines, not strict rules - document however seems best.
A README for a firmware-only project (e.g. Babydriver, MPXE, bootloader, CAN explorer) should answer the following questions:
- What is it?
- What problem does it solve?
- How do I use it? (with usage examples / example commands, etc)
- How does it work? (architectural overview)
A README for a board project (powering a hardware board, e.g. power distribution, centre console, charger, BMS carrier) should answer the following questions:
- What is the purpose of the board?
- What are all the things that the firmware needs to do?
- How does it fit into the overall system?
- How does it work? (architectural overview, e.g. what each module's purpose is or how data flows through the firmware)
-->
# simulation

6 changes: 6 additions & 0 deletions projects/simulation/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"libs": [
"FreeRTOS",
"ms-common"
]
}
38 changes: 38 additions & 0 deletions projects/simulation/inc/operation_listener.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma once

#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/can.h>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't need CAN

#include <linux/can/raw.h>
#include <net/if.h>
#include <poll.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#include "adc.h"
#include "gpio.h"
#include "gpio_it.h"
#include "i2c.h"
#include "log.h"

#define x86 1
#define PORT 2520

void sim_init(int sock_num);

typedef enum {
GPIO_SET = 0,
GPIO_TOGGLE,
GPIO_IT_TRIGGER,
ADC_SET_READING,
I2C_SET_READING,
SPI_SET_RX,
UART
} Operations;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just add a NUM_OF_OPERATIONS at the end

188 changes: 188 additions & 0 deletions projects/simulation/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
#include "operation_listener.h"
#include "spi.h"

bool s_keep_alive = true;

void sim_init(int sock_num) {
char buffer[2024];
LOG_DEBUG("Simulation thread started\n");
int res;
int operation, length, param1, param2, param3;
char rcv[1];
int p;
Operations input;

while (s_keep_alive) {
res = 0;
memset(buffer, 0, sizeof(buffer));
p = 0;
LOG_DEBUG("Listening\n");
while (s_keep_alive) {
memset(rcv, 0, sizeof(rcv));
res = recv(sock_num, rcv, 1, 0);
if (res == 1) {
if (rcv[0] != '\n') {
buffer[p] = rcv[0];
p++;
} else {
break;
}
}
}
LOG_DEBUG("Message received!\n");
param1 = 0;
param2 = 0;
param3 = 0;
sscanf(buffer, "%d: %d, %[^\n\t]", &operation, &length, buffer);
if (operation < 0 || operation > 6) {
LOG_DEBUG("Invalid operation: %d\n", operation);
continue;
}

input = operation;
switch (input) {
case GPIO_SET:
LOG_DEBUG("GPIO_SET\n");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm could you just put each operation in a function? It just makes it easier to read

if (length != 3) {
LOG_DEBUG("Invalid length for operation: %d Length: %d\n", operation, length);
break;
}

sscanf(buffer, "%d, %d, %d", &param1, &param2, &param3);
if (param1 < 0 || param2 < 0 || param3 < 0 || param1 > 6 || param2 > 16 || param3 > 1) {
LOG_DEBUG("Invalid param, 1: %d, 2: %d, 3: %d\n", param1, param2, param3);
continue;
}

GpioAddress GPIO_SET_ADDR = { .port = param1, .pin = param2 };
gpio_set_state(&GPIO_SET_ADDR, param3);
break;
case GPIO_TOGGLE:
LOG_DEBUG("GPIO_TOGGLE\n");
if (length != 2) {
LOG_DEBUG("Invalid length for operation: %d Length: %d\n", operation, length);
break;
}

sscanf(buffer, "%d, %d, %d", &param1, &param2, &param3);
if (param1 < 0 || param2 < 0 || param3 < 0 || param1 > 6 || param2 > 16) {
LOG_DEBUG("Invalid param, 1: %d, 2: %d, 3: %d\n", param1, param2, param3);
continue;
}

GpioAddress GPIO_TOGGLE_ADDR = { .port = param1, .pin = param2 };
gpio_toggle_state(&GPIO_TOGGLE_ADDR);
break;
case GPIO_IT_TRIGGER:
LOG_DEBUG("GPIO_IT_TRIGGER\n");
if (length != 2) {
LOG_DEBUG("Invalid length for operation: %d Length: %d\n", operation, length);
break;
}

sscanf(buffer, "%d, %d, %d", &param1, &param2, &param3);
if (param1 < 0 || param2 < 0 || param3 < 0 || param1 > 6 || param2 > 16) {
LOG_DEBUG("Invalid param, 1: %d, 2: %d, 3: %d\n", param1, param2, param3);
continue;
}

GpioAddress IT_TRIGGER_ADDR = { .port = param1, .pin = param2 };
gpio_it_trigger_interrupt(&IT_TRIGGER_ADDR);
break;
case ADC_SET_READING:
LOG_DEBUG("ADC_SET_READING\n");
if (length != 3) {
LOG_DEBUG("Invalid length for operation: %d Length: %d\n", operation, length);
break;
}

sscanf(buffer, "%d, %d, %d", &param1, &param2, &param3);
if (param1 < 0 || param2 < 0 || param3 < 0 || param1 > 6 || param2 > 16) {
LOG_DEBUG("Invalid param, 1: %d, 2: %d, 3: %d\n", param1, param2, param3);
continue;
}

GpioAddress ADC_SET_READING_ADDR = { .port = param1, .pin = param2 };
adc_set_reading(ADC_SET_READING_ADDR, param3);
break;
case I2C_SET_READING:
LOG_DEBUG("I2C_SET_READING\n");
if (length != 3) {
LOG_DEBUG("Invalid length for operation: %d Length: %d\n", operation, length);
break;
}

sscanf(buffer, "%d, %d, %[^\n\t]", &param1, &param2, buffer);
if (param1 < 0 || param2 < 0 || param1 > 1) {
LOG_DEBUG("Invalid param, param1: %d, param2: %d\n", param1, param2);
continue;
}

I2CPort i2c_port = param1;
i2c_set_data(i2c_port, (uint8_t *)&buffer, (size_t)param2);
break;
case SPI_SET_RX:
LOG_DEBUG("SPI_SET_RX\n");
if (length != 2) {
LOG_DEBUG("Invalid length for operation: %d Length: %d\n", operation, length);
break;
}

sscanf(buffer, "%d, %[^\n\t]", &param1, buffer);
if (param1 < 0) {
LOG_DEBUG("Invalid param, param1: %d, param2: %d\n", param1, param2);
continue;
}

spi_set_rx((uint8_t *)&buffer, param1);
break;
case UART:
LOG_DEBUG("UART\n");
break;
default:
LOG_DEBUG("UNRECOGNIZED OPERATION: %d\n", input);
}
usleep(1000000);
}
}

#ifdef x86
int main(int argc, char *argv[]) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be getting the port from the args, but this is fine for now

LOG_DEBUG("Operation listener thread started\n");
int socketfd = socket(AF_INET, SOCK_STREAM, 0);
if (socketfd < 0) {
LOG_DEBUG("Socket error: %d", socketfd);
return 0;
}
LOG_DEBUG("Socket successful\n");
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(2520);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int status = bind(socketfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (status < 0) {
LOG_DEBUG("Bind failed: %d\n", status);
return 0;
}
LOG_DEBUG("Bind successful\n");
if (listen(socketfd, 5) < 0) {
LOG_DEBUG("Listen failed\n");
return 0;
}
LOG_DEBUG("Listen successful\n");
int newsockfd = accept(socketfd, NULL, NULL);
if (newsockfd < 0) {
LOG_DEBUG("Accept failed: %d \n", newsockfd);
return 0;
}
LOG_DEBUG("Accept successful\n");

sim_init(newsockfd);
close(newsockfd);
close(socketfd);
}
#else
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no if. This should only ever run on x86

int main(int argc, char *argv[]) {
LOG_DEBUG("Operation listener thread started");
}
#endif
60 changes: 60 additions & 0 deletions projects/simulation/src/simulation_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <poll.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#include "gpio.h"
#include "gpio_it.h"
#include "log.h"

#define PORT 2520

int main() {
int socketfd;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also consider putting this socket logic into a function so other users don't need to copy this

struct sockaddr_in server_addr;
socketfd = socket(AF_INET, SOCK_STREAM, 0);
if (socketfd < 0) {
LOG_DEBUG("Socket error: %d \n", socketfd);
return 0;
}
LOG_DEBUG("Socket successful\n");

server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

if (connect(socketfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
LOG_DEBUG("Connect error\n");
return 0;
}
LOG_DEBUG("Connect successful\n");
const char *test1 = "0: 3, 2, 16, 0\n";
const char *test2 = "1: 2, 2, 16\n";
const char *test3 = "2: 2, 2, 16\n";
const char *test4 = "3: 3, 2, 16, 3\n";
const char *test5 = "4: 3, 1, 5, hello\n";
const char *test6 = "5: 3, 1, 5, hello\n";
const char *test7 = "6: 3, 2, 5, hello\n";
const char *test8 = "7: 3, 2, 16, 0";
send(socketfd, test1, strlen(test1), 0);
send(socketfd, test2, strlen(test2), 0);
send(socketfd, test3, strlen(test3), 0);
send(socketfd, test4, strlen(test4), 0);
send(socketfd, test5, strlen(test5), 0);
send(socketfd, test6, strlen(test6), 0);
send(socketfd, test7, strlen(test7), 0);
send(socketfd, test8, strlen(test8), 0);
close(socketfd);
return 0;
}
Loading