This page collects a number of more technical topics about the IMGe Interaction Device.
If you have any questions, feel free to contact me at huberma@in.tum.de
Protocol summary
The following commands are supported by the latest firmware:
Command
Write string
Receive string
Example
Exercise
Query GPIO
"1"
32 bit GPIO register as hex string
"1" -> "00000120"
1
Interrupt driven Button events
"2"
Event messages "E: x" or "None"; uppercase indicates pressed, lowercase released
"2" -> "E: C"
2
Extended Button events
"3"
Button event data with timestamps as 32 bit hex string
"3" -> "E: d 0000198B"
2
Query Analog ports
"4"
4 times 16 bit ADC values as hex strings prefixed by "A: "
"4" -> "A: 0856 0FFE 0003 0000"
3
LED control
"l x y\r\n", x is LED number (0 to 3), y is either 0: off, 1: on or 2: toggle
"Done."
"l 1 2\r\n" -> "Done."
4
Motor control
"m x\r\n", x is motor power (0 to 1000)
"Done."
"m 300\r\n" -> "Done."
4
Query Accelerometer
"a"
3 times signed 8 bit accelerometer values as hex strings prefixed with "Accel: "
"a" -> "Accel: 04 FE C3"
5
Debug: Toggle all outputs
"5"
"Ok"
"5" -> "Ok"
-
Debug: Get firmware version
"v"
Version ID string
"v" -> "IMGe Device Version T6 .9 Hash: 6fb8d918a97c451e900da197ae65777320f6968f"
-
The device acts as a USB CDC class device with ACM profile.
For windows you need virtual COM-port drivers to access this interface.
For linux no non-native drivers should be necessary
The device should appear as /dev/ttyUSBX or /dev/ttyACMX (check dmesg output when in doubt)
Communications via C/C++
Example for doing serial communicaitons in C/C++ on Linux/Mac or Windows
Linux/Mac version:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <iostream>
#include <cstring>
char readBuf[8];
char stringBuffer[64];
int main() {
int fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY | O_NDELAY); // On Mac: find correct devices using Terminal ls /dev/tty.*
if(fd == -1) {
perror("Unable to open serial port\n");
return (0);
}
std::cout << "Serial Port opened\n";
int res = 0;
char* recPtr = stringBuffer;
while(1) {
// Write to Serial Port (Write the character "4" for ADC values)
res = write(fd, "4", 1);
if (res != -1) {
std::cout << "Write OK" << std::endl;
} else {
std::cout << "Error writing to serial port" << std::endl;
}
memset(readBuf, 0x00, 8);
memset(stringBuffer, 0x00, 64);
recPtr = stringBuffer;
// Read from Serial Port
while (1) {
res = read(fd,readBuf,1);
if (res > 0) {
// stop at end of line
if (readBuf[0]==0x0d) {
// flush rest of available characters
while (read(fd,readBuf,1)>0)
;
break;
} else {
*recPtr = readBuf[0];
recPtr++;
}
}
}
std::cout << "Read string: " << stringBuffer << std::endl;
// Write to Serial Port (Write "1" for button register
res = write(fd, "1", 1);
if (res != -1) {
std::cout << "Write OK" << std::endl;
} else {
std::cout << "Error writing to serial port" << std::endl;
}
memset(readBuf, 0x00, 8);
memset(stringBuffer, 0x00, 64);
recPtr = stringBuffer;
// Read from Serial Port
while (1) {
res = read(fd,readBuf,1);
if (res > 0) {
// stop at end of line
if (readBuf[0]==0x0d) {
// flush rest of available characters
while (read(fd,readBuf,1)>0)
;
break;
} else {
*recPtr = readBuf[0];
recPtr++;
}
}
}
std::cout << "Read string: " << stringBuffer << std::endl;
}
close(fd);
return (0);
}
Windows version:
#include "stdafx.h"
#include <iostream>
#include <windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hSerial;
DWORD bytesTransferred;
hSerial = CreateFileA("COM3", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hSerial == INVALID_HANDLE_VALUE) {
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
std::cout << "Port not found" << std::endl;
} else {
std::cout << "Cannot open port" << std::endl;
}
} else {
std::cout << "Serial port openend" << std::endl;
}
// Set timeouts to 0 for non-blocking reading
COMMTIMEOUTS timeouts;
memset((void *)&timeouts, 0x00, sizeof(timeouts));
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(hSerial, &timeouts);
char readBuffer[8];
char stringBuffer[128];
char* recPtr = stringBuffer;
while(1) {
// Write "1" to get the button register
if (WriteFile(hSerial, "1", 1, &bytesTransferred, NULL)) {
std::cout << "Cannot write to serial port" << std::endl;
} else {
std::cout << "Write OK" << std::endl;
}
memset((void *)readBuffer, 0x00, 8);
memset((void *)stringBuffer, 0x00, 128);
recPtr = stringBuffer;
while(1) {
int res = ReadFile(hSerial, readBuffer, 1, &bytesTransferred, NULL);
if (res && bytesTransferred) {
if (readBuffer[0] == 0x0d) {
while (ReadFile(hSerial, readBuffer, 1, &bytesTransferred, NULL) && bytesTransferred)
;
break;
} else {
*recPtr++ = readBuffer[0];
}
}
}
std::cout << "Read string: " << stringBuffer << std::endl;
// Write "4" to read the ADCs
if (WriteFile(hSerial, "4", 1, &bytesTransferred, NULL)) {
std::cout << "Cannot write to serial port" << std::endl;
} else {
std::cout << "Write OK" << std::endl;
}
memset((void *)readBuffer, 0x00, 8);
memset((void *)stringBuffer, 0x00, 128);
recPtr = stringBuffer;
while(1) {
int res = ReadFile(hSerial, readBuffer, 1, &bytesTransferred, NULL);
if (res && bytesTransferred) {
if (readBuffer[0] == 0x0d) {
while (ReadFile(hSerial, readBuffer, 1, &bytesTransferred, NULL) && bytesTransferred)
;
break;
} else {
*recPtr++ = readBuffer[0];
}
}
}
std::cout << "Read string: " << stringBuffer << std::endl;
}
return 0;
}
Hardware
The basis of the interaction device is the STMicroelectronics ARM development board "ST32F4Discovery". You can order one of these for example from RS-Components. Search for "STM32F4DISCOVERY" or order code "745-8434".
The development board is extended by two daughterboards, the IMGE-C-PCB Cover board (no functionality, only cover) and the IMGE-I-PCB Interaction Board.
You can find the files for schematics and the layouts here.
The design was done using the open EDA suite Kicad, but also PDFs for schematics and PCB layout layers are included.
Furthermore Bills of Materials (bom.txt files) are included, detailing the required components and possible sources (in german only so far, sorry).
Firmware
Source
The firmware was compiled using the GCC-Toolchain for ARM targets, such as GNU ARM or YAGARTO for example.
You can find the current version of the firmware here: https://github.com/ponymorphism/imge-cactus-firmware . It is in some parts based on the example projects and device libraries from STMicroelectronics.
To compile, enter the "main" subdirectory and just call "make". The resulting image will be called "main.bin" which you can flash on your own devices using the methods detailed below.
Do not try to re-flash devices in the games labs. If you need to change something on these devices, contact us.