There is no support for Serial IO at the moment, which is a big shame, as it'd be a great addition to AGK. In particular with the popularity of various entry-level Microcontroller Dev-Boards like Arduino, Teensy, PIC and so on. Imagine being able to write front end software using AppGameKit to send and receive data to these microcontrollers?! You could have an AppGameKit app that worked as a remote-control to a RC quad-copter. AppGameKit front-end to 'smart-home' control of everything from the temperature on the bathroom floor in the morning to automatically opening the garage door for you as you start the engine of your car.
What we'd need is Serial communication over USB and Bluetooth built into AGK. such IO interfaces are standard on all devices AppGameKit run on. Well, maybe not Bluetooth on Desktop PCs/Macs, but details.
Now, there are work-arounds. But they are cumbersome and require an extra layer of hardware and protocols. You can use HTTP to send data out of AppGameKit, and receive data as a file containing data you need. This is slow and do not allow a stream of data to be transferred.
In a project I am working on now, I am in need of polling Serial In at a frequency of up to twice per second. The HTTP approach just won't do. There is however the Joystick. Through the Joystick device, several bytes of data can be imported as a steady stream. There is no package control or buffer-stack per-se, so data need be pre-formatted and unpacked before sending it into AppGameKit as an emulated joystick device. Which, I might add is a USB device, so the underlying code to read from Serial USB is already in AppGameKit - it is just not opened up for us to read and write to using our own package structures and protocol settings (baud rate, stop bits, parity etc)
Anyway. to make my project work, I've set up an Arduino UNO R3 as a Joystick. This reads data from a DB9 RS232 FTDI to TTL converter, assigns the datapackages to 4 Joystick-Axis acting as a byte each, and 8 buttons acting as 1 byte of 8 bits. So in total 5 bytes being streamed into AGK. This works ok for the most part, but there are some idiosyncrasies with the Axis as a byte conversion.
Anyhow, the example code - first the Arduino:
/* ****************************************
* HW: Arduino UNO R3
*
* RS232 data IN to
* USB data OUT converter
*
* Takes all parameters from the RS232
* data-stream, converts into emulated
* Joystick buttons and axis states for
* transfer into AGK app.
*
* Licence: CC BY Roy Dybing
* Version: 0.2 - February 2016
* ****************************************/
/* ****************************************
* Imports
* ****************************************/
#include "UnoJoy.h"
#include <SoftwareSerial.h>
/* ****************************************
* Globals
* ****************************************/
// Constants
#define rxPin 2 // softSerial in
#define txPin 3 // softSerial out
#define buStart 8 // button for setting active/inactive mode
#define ledActive 9 // LED to signal active/inactive mode
// Variables
char bufferStart; // package wrapper Start
unsigned long newTimer; // button debounce timer control
unsigned long dBounceTimer = 10;// button debounce interval
boolean joyActive = false;
// Arrays
byte bufferIn[8];
byte bufferOut[6];
int buActive[2]; // 0 = inactive || 1 = engaged || 2 = active
unsigned long buTimer[2];
// Objects
SoftwareSerial rs232 = SoftwareSerial(rxPin, txPin);
void setup(){
/* ****************************************
* Setting up IO initial state
* ****************************************/
//Serial.begin(19200); // debug only
rs232.begin(19200);
setupUnoJoy();
// set pins
pinMode(buStart, INPUT_PULLUP);
pinMode(ledActive, OUTPUT);
digitalWrite(ledActive, LOW);
// set all button states off
buTimer[1] = 0;
buActive[1] = 0;
// initialize timers
newTimer = millis();
}
void loop(){
/* ****************************************
* Main Loop
* - check if incoming data
* - read and transfer data to variables
* - assign variables to output-channels
* buttons 1..8 = byte 1
* lX = byte 2
* lY = byte 3
* rX = byte 4
* rY = byte 5
* ****************************************/
newTimer = millis();
// Start - Stop button
if (digitalRead(buStart) == LOW){
if (buActive[1] == 0){
buActive[1] = 1;
buTimer[1] = newTimer;
}
if ((buActive[1] == 1) && ((buTimer[1] + dBounceTimer) < newTimer)){
buActive[1] = 2;
}
}
else if ((digitalRead(buStart) == HIGH) && (buActive[1] == 2)){
switch (joyActive){
case false:
joyActive = true;
digitalWrite(ledActive, HIGH);
break;
case true:
joyActive = false;
digitalWrite(ledActive, LOW);
break;
}
buActive[1] = 0;
}
// fill bufferIn
if (rs232.available() > 0){
delay(10); // allow time for buffer to fill up
bufferStart = rs232.read();
// check for package start character
if (bufferStart == 'S'){
for (int i = 1; i < 7; i++){
bufferIn[i] = rs232.read();
}
bufferIn[0] = bufferStart;
// check for package end character
if (bufferIn[6] == 'E'){
// transfer from incoming buffer to outgoing buffer
for (int i = 1; i < 6; i++){
bufferOut[i] = bufferIn[i];
}
}
}
// reset wrappers and start-control
bufferIn[0] = 0;
bufferIn[6] = 0;
bufferStart = 'x';
}
//Send data out if active
if (joyActive == true){
// reset
dataForController_t controllerData = getControllerData();
// buttons 1..8 = byte 1
controllerData.squareOn = bitRead(bufferOut[1], 0); // bit 1
controllerData.crossOn = bitRead(bufferOut[1], 1); // bit 2
controllerData.circleOn = bitRead(bufferOut[1], 2); // bit 3
controllerData.triangleOn = bitRead(bufferOut[1], 3); // bit 4
controllerData.l1On = bitRead(bufferOut[1], 4); // bit 5
controllerData.r1On = bitRead(bufferOut[1], 5); // bit 6
controllerData.l2On = bitRead(bufferOut[1], 6); // bit 7
controllerData.r2On = bitRead(bufferOut[1], 7); // bit 8
// transfer 4 bytes through Joystick Axis
controllerData.leftStickX = bufferOut[2]; // byte 2
controllerData.leftStickY = bufferOut[3]; // byte 3
controllerData.rightStickX = bufferOut[4]; // byte 4
controllerData.rightStickY = bufferOut[5]; // byte 5
//send
setControllerData(controllerData);
}
}
/* ****************************************
* define and zero all buttons and axis
* ****************************************/
dataForController_t getControllerData(void){
dataForController_t controllerData = getBlankDataForController();
// buttons as mapped by PS3 controller
// byte 1
controllerData.triangleOn = 0; // bit 1
controllerData.circleOn = 0; // bit 2
controllerData.squareOn = 0; // bit 3
controllerData.crossOn = 0; // bit 4
controllerData.l1On = 0; // bit 5
controllerData.r1On = 0; // bit 6
controllerData.l2On = 0; // bit 7
controllerData.r2On = 0; // bit 8
// axis
controllerData.leftStickX = 0; // byte 3
controllerData.leftStickY = 0; // byte 4
controllerData.rightStickX = 0; // byte 5
controllerData.rightStickY = 0; // byte 6
// return the data
return controllerData;
}
To set the Arduino up as a Joystick readable by AppGameKit, you'll need to program the USB controller on the Arduino as a Joystick. Batch files for this (and reverting back to an Arduino) and a comprehensive how-to is in included with the Unojoy library download.
...and on the AppGameKit end to read it:
// initialize external joystick
CompleteRawJoystickDetection()
SetRawJoystickDeadZone(0)
do
serialTranslate(1)
sync()
loop
function serialTranslate(in)
// Axis
joy1X# = getRawJoystickX(in)
joy1Y# = getRawJoystickY(in)
joy2X# = getRawJoystickZ(in)
joy2Y# = getRawJoystickRZ(in)
byte2 = convert(joy1X#)
byte3 = convert(joy1Y#)
byte4 = convert(joy2X#)
byte5 = convert(joy2Y#)
// Buttons 0..7
byte1 = 0
doubler = 1
for i = 1 to 8
if getRawJoystickButtonState(in, i) = 1
byte1 = byte1 + doubler
endif
doubler = doubler * 2
next i
print("byte1: " + str(byte1))
print("byte2: " + str(byte2))
print("byte3: " + str(byte3))
print("byte4: " + str(byte4))
print("byte5: " + str(byte5))
endFunction
function convert(jIn#)
// convert to 0..255 from -1 to 1
// make input range from 0 to 1
jIn# = (jIn# + 1) / 2
// get byte value
jIn# = jIn# * 255
// round result
jOut = round(jIn#)
endFunction jOut