-
Notifications
You must be signed in to change notification settings - Fork 4
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
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"libs": [ | ||
"FreeRTOS", | ||
"ms-common" | ||
] | ||
} |
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> | ||
#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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe just add a |
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"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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", ¶m1, ¶m2, ¶m3); | ||
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", ¶m1, ¶m2, ¶m3); | ||
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", ¶m1, ¶m2, ¶m3); | ||
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", ¶m1, ¶m2, ¶m3); | ||
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]", ¶m1, ¶m2, 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]", ¶m1, 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[]) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't need CAN