1
0
Fork 0

Compare commits

..

No commits in common. "54f73ccaf2f082e586818279ed737e1d1b5736e1" and "f34d81ad878f2c92e32512bcc50ad82353c73066" have entirely different histories.

4 changed files with 0 additions and 447 deletions

View file

@ -1,118 +0,0 @@
#include <Wire.h>
#include <inttypes.h>
static const int eeprom_addr = 0b1010000;
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() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
Wire.begin();
//Serial.println("Arduino started");
}
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();
}

View file

@ -1,71 +0,0 @@
#include <Wire.h>
#include <inttypes.h>
static const int eeprom_addr = 0b1010000;
uint8_t pageData[128] = {};
uint16_t pageAddr = 0;
void write_addr(uint16_t addr) {
Wire.write((uint8_t)(addr >> 8));
Wire.write((uint8_t)addr);
}
uint16_t sum_complement(const uint8_t data[128]) {
uint16_t sum = 0;
for (int i = 0; i<128; i += 2) {
sum += (data[i+1] << 8) | data[i];
}
return -sum;
}
void setup() {
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
Wire.begin();
}
void loop() {
char ret[4] = "";
// put your main code here, to run repeatedly:
do {
if (!Serial.readBytesUntil('\n', ret, 2))
Serial.read();
} 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 < 512; i++) {
memset(pageData, 0, 128);
// Arduino I2C buffer is 32 bytes, so we need multiple requests per page.
for (int j = 0; j < 4; j++) {
Wire.requestFrom(eeprom_addr, 32);
for (int k = 0; k < 32; k++) {
pageData[32*j + k] = Wire.read();
}
}
// Try to send the full page until the recipient ACKs
uint16_t page_checksum = sum_complement(pageData);
do {
memset(ret, 0, 4);
size_t written = 0;
while (written < 128) {
written += Serial.write(pageData + written, min(128 - written, 64));
}
Serial.write((uint8_t*)&page_checksum, 2);
while(!Serial.readBytesUntil('\n', ret, 3));
Serial.read();
} while(strncmp(ret, "ACK", 3) != 0);
}
digitalWrite(LED_BUILTIN, LOW);
}

View file

@ -1,247 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using UnityEngine;
using UnityEngine.UIElements;
// Handle the serial communication with the Arduino,
// the cartridge transfer and related UI interactions.
public class Arduino_Com : MonoBehaviour
{
private enum ArduinoState
{
Déconnecté,
Connecté,
Lecture,
Écriture,
Invalide
}
// ======== UI ========
[SerializeField] private UIDocument ui;
private DropdownField _arduinoSerialPort;
private EnumField _arduinoState;
private Button _arduinoControlButton;
private ProgressBar _arduinoProgress;
private Button _cartLoadButton;
private Button _cartWriteButton;
private VisualElement _cartImage;
// ======== IO ========
private SerialPort _serial = new ();
// Probably should be left alone but give the possibility to change it in the inspector.
[SerializeField] private int baudrate = 115200;
private string _activeSerialPort;
private ArduinoState _state = ArduinoState.Déconnecté;
private string _cartPath;
private FileStream _cart;
// ======== Cart transfer ========
// Page data corresponding to the EEPROM.
private const int PageSize = 128;
private const int PageCount = 512;
// Page to be written out.
private Byte[] _pageBuffer = new byte[PageSize];
// Current position in _pageBuffer.
private int _readBytes;
private int _currentPage;
// Checksum a 128 bytes page of data by summing it into an unsigned 16 bits int,
// to be used either as a verification with a received checksum or to negate and
// send as the checksum.
private static UInt16 ComputeChecksum(Byte[] data)
{
if (data.Length != PageSize)
{
throw new InvalidDataException("Checksum only accepts "+PageSize+" bytes arrays !");
}
UInt16 sum = 0;
for (var i = 0; i < PageSize; i += 2)
{
sum += BitConverter.ToUInt16(data, i);
}
return sum;
}
private IEnumerator<WaitUntil> ReceiveSerialData()
{
do
{
yield return new WaitUntil(() => _serial.BytesToRead >= 1);
// Read all available data, up to the PageSize.
_readBytes += _serial.Read(_pageBuffer, _readBytes, PageSize - _readBytes);
// Full page received, check checksum and ACK/NAK, write received page.
if (_readBytes >= 128)
{
Byte[] checksum = new byte[2];
// There might be less than the two characters of the checksum available, loop until complete.
var checksumRead = 0;
do
{
checksumRead += _serial.Read(checksum, checksumRead, 2-checksumRead);
} while (checksumRead < 2);
// Implicit type of the sum is 4 bytes, so the overflow doesn't occur. Compute manually.
if (65536 - (BitConverter.ToUInt16(checksum) + ComputeChecksum(_pageBuffer)) == 0)
{
// Checksum valid, write it out to the cart.
_cart.Write(_pageBuffer);
_currentPage += 1;
_serial.Write("ACK\n");
}
else
{
// Checksum invalid, ask for retransmit.
_serial.Write("NAK\n");
Debug.LogWarningFormat("Page {0} reception failed, asking for retransmit.", _currentPage);
}
_readBytes = 0;
}
} while (_currentPage < PageCount);
// We are done receiving the cart, we don't expect more data to be received so the coroutine can return.
_currentPage = 0;
_state = ArduinoState.Connecté;
_cart.Close();
// Re-enable buttons now that the transfer is done.
_arduinoControlButton.SetEnabled(true);
_cartLoadButton.SetEnabled(true);
// _cartWriteButton.SetEnabled(true); TODO: Not implemented
_arduinoProgress.visible = false;
// Update cart image !
var newCartTexture = new Texture2D(2, 2);
var textureData = File.ReadAllBytes(_cartPath);
newCartTexture.LoadImage(textureData);
_cartImage.style.backgroundImage = new StyleBackground(newCartTexture);
}
void Start()
{
// ======== UI ========
var uiRoot = ui.rootVisualElement;
_arduinoSerialPort = uiRoot.Query<DropdownField>("Arduino-Serial");
_arduinoSerialPort.RegisterValueChangedCallback(OnNewSerialPort);
_arduinoSerialPort.choices = new List<string>(SerialPort.GetPortNames());
_arduinoState = uiRoot.Query<EnumField>("Arduino-State");
_arduinoControlButton = uiRoot.Query<Button>("Arduino-Button");
_arduinoControlButton.clickable.clicked += OnArduinoButtonClicked;
_arduinoProgress = uiRoot.Query<ProgressBar>("Arduino-Progress");
_arduinoProgress.highValue = PageCount;
_cartLoadButton = uiRoot.Query<Button>("Cart-Load");
// Cart buttons can't work if the Arduino is not connected.
_cartLoadButton.SetEnabled(false);
_cartLoadButton.clickable.clicked += OnLoadButtonClicked;
_cartWriteButton = uiRoot.Query<Button>("Cart-Write");
_cartWriteButton.SetEnabled(false);
_cartImage = uiRoot.Query<VisualElement>("Cart");
// ======== IO ========
_cartPath = Application.temporaryCachePath + "/cart.png";
}
void Update()
{
// Update the serial ports list so we can detect hot-plugs.
_arduinoSerialPort.choices.Clear();
_arduinoSerialPort.choices.AddRange(SerialPort.GetPortNames());
// Update state enum and progress bar if active.
_arduinoState.value = _state;
if (_state is ArduinoState.Lecture or ArduinoState.Écriture)
_arduinoProgress.value = _currentPage;
}
private void OnDestroy()
{
_arduinoControlButton.clickable.clicked -= OnArduinoButtonClicked;
_cartLoadButton.clickable.clicked -= OnLoadButtonClicked;
_arduinoSerialPort.UnregisterValueChangedCallback(OnNewSerialPort);
if (_serial.IsOpen)
_serial.Close();
_cart?.Close();
}
void OnLoadButtonClicked()
{
// Don't allow arduino actions during load.
_arduinoControlButton.SetEnabled(false);
_cartLoadButton.SetEnabled(false);
_cartWriteButton.SetEnabled(false);
_arduinoProgress.visible = true;
// Clean up eventual previous cartridge.
if (File.Exists(_cartPath))
File.Delete(_cartPath);
// Open the file, ready for transfers.
_cart = File.OpenWrite(_cartPath);
// Start listening to incoming data asynchronously.
StartCoroutine(ReceiveSerialData());
_serial.Write("GO\n");
_state = ArduinoState.Lecture;
}
void OnArduinoButtonClicked()
{
if (_state == ArduinoState.Connecté)
{
if (_serial.IsOpen)
_serial.Close();
_arduinoControlButton.text = "Connecter";
_cartLoadButton.SetEnabled(false);
_cartWriteButton.SetEnabled(false);
_arduinoSerialPort.SetEnabled(true);
_state = ArduinoState.Déconnecté;
}
else if (_state == ArduinoState.Déconnecté)
{
// Set baudrate again here in case it was changed in the inspector.
_serial.BaudRate = baudrate;
_serial.PortName = _activeSerialPort;
_serial.Open();
if (!_serial.IsOpen)
{
Debug.Log("Failed to connect to serial");
return;
}
// TODO: Wait ~2s for Arduino startup
_arduinoControlButton.text = "Déconnecter";
_cartLoadButton.SetEnabled(true);
// _cartWriteButton.SetEnabled(true); TODO: Not implemented
_arduinoSerialPort.SetEnabled(false);
_state = ArduinoState.Connecté;
}
}
// The serial port should not be changeable when connected.
void OnNewSerialPort(ChangeEvent<string> newPort)
{
if (Equals(newPort.newValue, _activeSerialPort))
return;
_activeSerialPort = newPort.newValue;
// Might be a slight race condition here if a port is removed in-between updates when clicked, so check anyway.
_state = SerialPort.GetPortNames().Contains(newPort.newValue) ? ArduinoState.Déconnecté : ArduinoState.Invalide;
_arduinoControlButton.SetEnabled(_state != ArduinoState.Invalide);
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: cc2a8d09604e9e8f5945bee6e08a173c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: