Arduino: Add full Arduino code
This is the full working Arduino code, for writing and loading. This shouldn not be used by students.
This commit is contained in:
parent
f34d81ad87
commit
dfe7b6b5d0
2 changed files with 215 additions and 0 deletions
117
Arduino/ReceiveCart/ReceiveCart.ino
Normal file
117
Arduino/ReceiveCart/ReceiveCart.ino
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
static const int eeprom_addr = 0b1010000;
|
||||||
|
|
||||||
|
// Send a two bytes address via I²C which selects an address within the EEPROM.
|
||||||
|
void write_addr(uint16_t addr) {
|
||||||
|
Wire.write((uint8_t)(addr >> 8));
|
||||||
|
Wire.write((uint8_t)addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_page(uint8_t page[128], uint16_t page_addr) {
|
||||||
|
uint8_t bytes_written = 0;
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
int ret;
|
||||||
|
int write_bytes = min(128 - bytes_written, 30);
|
||||||
|
do {
|
||||||
|
Wire.beginTransmission(eeprom_addr);
|
||||||
|
write_addr(page_addr + bytes_written);
|
||||||
|
Wire.write(page + bytes_written, write_bytes);
|
||||||
|
ret = Wire.endTransmission();
|
||||||
|
delay(5);
|
||||||
|
} while (ret != 0);
|
||||||
|
bytes_written += write_bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_sumcomplement(uint8_t data[128], uint16_t checksum) {
|
||||||
|
uint16_t sum = 0;
|
||||||
|
for (int i = 0; i<128; i += 2) {
|
||||||
|
sum += (data[i+1] << 8) | data[i];
|
||||||
|
}
|
||||||
|
sum += checksum;
|
||||||
|
return !sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
volatile uint8_t pageData[128] = {};
|
||||||
|
volatile uint16_t pageChecksum = 0;
|
||||||
|
volatile uint16_t pageAddr = 0;
|
||||||
|
volatile bool pageOk = false;
|
||||||
|
volatile bool reicivingCart = false;
|
||||||
|
volatile uint32_t last_page_update = 0;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
Wire.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
if (reicivingCart && millis() - last_page_update > 1000) {
|
||||||
|
Serial.print("TO");
|
||||||
|
reicivingCart = false;
|
||||||
|
pageOk = false;
|
||||||
|
pageAddr = 0;
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
delay(500);
|
||||||
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
delay(500);
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
delay(500);
|
||||||
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageOk) {
|
||||||
|
pageOk = false;
|
||||||
|
bool pageValid = check_sumcomplement((uint8_t *)pageData, pageChecksum);
|
||||||
|
Serial.print(pageValid ? "ACK" : "NAK");
|
||||||
|
if (pageValid) {
|
||||||
|
write_page(pageData, pageAddr);
|
||||||
|
pageAddr += 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for (int i = 0; i<128; i++) {
|
||||||
|
if (i%16 == 0)
|
||||||
|
Serial.println();
|
||||||
|
Serial.print(pageData[i], HEX);
|
||||||
|
Serial.print(" ");
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
Serial.println(pageChecksum, HEX);*/
|
||||||
|
|
||||||
|
Serial.print("OK");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialEvent() {
|
||||||
|
static size_t read = 0;
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
if (Serial.available() == 5) {
|
||||||
|
char control[4] = {};
|
||||||
|
Serial.readBytesUntil('\n', control, 4);
|
||||||
|
Serial.read(); /* Drop the '\n' */
|
||||||
|
if (!strncmp(control, "CART", 4)) {
|
||||||
|
reicivingCart = true;
|
||||||
|
Serial.print("OK");
|
||||||
|
} else if (!strncmp(control, "DONE", 4)) {
|
||||||
|
reicivingCart = false;
|
||||||
|
} else {
|
||||||
|
Serial.print("KO");
|
||||||
|
}
|
||||||
|
pageOk = false;
|
||||||
|
pageAddr = 0;
|
||||||
|
read = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (reicivingCart && Serial.available() && read < 128) {
|
||||||
|
read += Serial.readBytes((char *)pageData+read, min(128-read, 64));
|
||||||
|
}
|
||||||
|
if (reicivingCart && read >= 128) {
|
||||||
|
pageOk = true;
|
||||||
|
Serial.readBytes((char*)&pageChecksum, 2);
|
||||||
|
read = 0;
|
||||||
|
}
|
||||||
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
last_page_update = millis();
|
||||||
|
}
|
98
Arduino/SendCart/SendCart.ino
Normal file
98
Arduino/SendCart/SendCart.ino
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
// Arduino constants
|
||||||
|
static constexpr uint8_t i2c_buff_size = 32;
|
||||||
|
static constexpr uint8_t serial_buff_size = 64;
|
||||||
|
|
||||||
|
// EEPROM constants
|
||||||
|
static constexpr int page_count = 512;
|
||||||
|
static constexpr int page_size = 128;
|
||||||
|
static constexpr int i2c_buff_per_page = page_size / i2c_buff_size;
|
||||||
|
static constexpr uint8_t eeprom_addr = 0b1010000;
|
||||||
|
|
||||||
|
uint8_t pageData[page_size] = {};
|
||||||
|
uint16_t pageAddr = 0;
|
||||||
|
|
||||||
|
// Send a two bytes address via I²C which selects an address within the EEPROM.
|
||||||
|
void write_addr(uint16_t addr) {
|
||||||
|
Wire.write((uint8_t)(addr >> 8));
|
||||||
|
Wire.write((uint8_t)addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the receiver sums on its side, it can just add this sum and check that is 0.
|
||||||
|
uint16_t sum_complement(const uint8_t data[page_size]) {
|
||||||
|
uint16_t sum = 0;
|
||||||
|
for (int i = 0; i<page_size; i += 2) {
|
||||||
|
sum += (data[i+1] << 8) | data[i];
|
||||||
|
}
|
||||||
|
return -sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
Wire.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read data from the Serial port until a full message is read.
|
||||||
|
* This function is blocking and will not return early, use with caution.
|
||||||
|
* Use '\n' as a delimiter for a complete message, making it exit
|
||||||
|
* early if it is encountered before the count is done (invalid message).
|
||||||
|
*/
|
||||||
|
void read_message(char *buffer, const uint8_t match_len) {
|
||||||
|
uint8_t read_bytes = 0;
|
||||||
|
do {
|
||||||
|
// readBytesUntil should always be positive or zero, despite the documentation.
|
||||||
|
read_bytes += Serial.readBytesUntil('\n', buffer + read_bytes, match_len - read_bytes);
|
||||||
|
} while(read_bytes < match_len || Serial.peek() == '\n');
|
||||||
|
if (Serial.peek() == '\n')
|
||||||
|
Serial.read(); // Consume the delimiter if it is there.
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
char ret[4];
|
||||||
|
// Wait until we receive the start message.
|
||||||
|
do {
|
||||||
|
memset(ret, 0, 4);
|
||||||
|
read_message(ret, 2);
|
||||||
|
} while (strncmp(ret, "GO", 2) != 0);
|
||||||
|
|
||||||
|
// Reset the EEPROM internal address to 0. It autoincrements after.
|
||||||
|
Wire.beginTransmission(eeprom_addr);
|
||||||
|
write_addr(0);
|
||||||
|
Wire.endTransmission(false);
|
||||||
|
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
/*
|
||||||
|
* We don't know the size of the cartridge, and it could be the whole EEPROM.
|
||||||
|
* Read and send all the pages (64kiB), it should not impact the final PNG.
|
||||||
|
*/
|
||||||
|
for (int i = 0; i < page_count; i++) {
|
||||||
|
memset(pageData, 0, page_size);
|
||||||
|
// Arduino I2C buffer is 32 bytes, so we need multiple requests per page.
|
||||||
|
for (int j = 0; j < i2c_buff_per_page; j++) {
|
||||||
|
Wire.requestFrom(eeprom_addr, i2c_buff_size);
|
||||||
|
for (int k = 0; k < i2c_buff_size; k++) {
|
||||||
|
pageData[i2c_buff_size*j + k] = Wire.read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to send the full page via serial until the recipient ACKs.
|
||||||
|
uint16_t page_checksum = sum_complement(pageData);
|
||||||
|
do {
|
||||||
|
// The internal Serial buffer is smaller than a page, so send in bursts.
|
||||||
|
size_t written = 0;
|
||||||
|
while (written < page_size) {
|
||||||
|
written += Serial.write(pageData + written, min(page_size - written, serial_buff_size));
|
||||||
|
}
|
||||||
|
Serial.write((uint8_t*)&page_checksum, 2);
|
||||||
|
|
||||||
|
memset(ret, 0, 4);
|
||||||
|
read_message(ret, 3);
|
||||||
|
} while(strncmp(ret, "ACK", 3) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue