Jay Jordison
Published © Apache-2.0

Injection projector- gaming console

This is my project for future gaming console's.

BeginnerFull instructions provided8 hours45
Injection projector- gaming console

Things used in this project

Hardware components

Tinker Board
Tinker Board
×1

Software apps and online services

Gigabits IoT Platform
Gigabits IoT Platform

Story

Read more

Custom parts and enclosures

img_20240126_160300_jtVK90Lm9v.png

Schematics

img_20240126_160300_ADj3DMUJbR.png

Code

console projector 2.ino

CSS
void setup() {
}

//define multiplexor pins
#define EN 7                    // D7 pin
#define S0 2                    // D2 pin
#define S1 3                    // D3 pin
#define S2 4                    // D4 pin
#define S3 5                    // D5 pin

// define screen mode directions
#define STOP 0                  // multiplexer C0 pin
#define DOWN 1                  // multiplexer C1 pin
#define UP 2                    // multiplexer C0 pin

// define analog pin for voltage sensor
#define VSensor A0              // A0 pin

// AV-receiver low and high limits for a trigger
const int TriggerLow = 3;       // if voltage is lower than the value, then the trigger is OFF
const int TriggerHigh = 7;      // if voltage is higher than the value, then the trigger is ON

// projector serial connection variables 
const byte numChars = 32;
char receivedChars[numChars];   //an array to store the received data

// projector state variables
boolean newData = false;
String ProjectorPowerState;
String ProjectorPreviousPowerState;

//screen constants
const int PullUpTime = 25000;   // full time from lower to upper position, milliseconds
const int PushDownTime = 19500; // time that requred to push down the screen to a working position; milliseconds


void setup() {
    // set digital pins mode
    pinMode(S0, OUTPUT); 
    pinMode(S1, OUTPUT); 
    pinMode(S2, OUTPUT); 
    pinMode(S3, OUTPUT);   
    pinMode(EN, OUTPUT);

    // initialize the multiplexer
    digitalWrite(S0, LOW);
    digitalWrite(S1, LOW);
    digitalWrite(S2, LOW);
    digitalWrite(S3, LOW);
    digitalWrite(EN, HIGH);

    Serial.begin(9600);   // console output for debug
    Serial1.begin(9600);  // projector serial connection
    ProjectorPreviousPowerState = "Unknown";
}

void loop() {
    int volt = analogRead(VSensor);            // read the input
    int voltage = map(volt,0,1023, 0, 2500);   // input voltage in centivolts. i.e. 3V = 300 cV
    Serial.println((String)"Trigger voltage in centivolts: " + voltage);

    if (Serial1.available()) {
        Serial.println("Projector serial connection is available, we need to check it state");
        recvWithEndMarker();

        // we need to get current projector state variable from the serial output
        if (newData == true) {  // only if we have a new data, we need to check the state
            newData = false;    // reset the new data flag
            ProjectorPowerState = String(receivedChars); // convert array to a sting
            ProjectorPowerState.trim(); // remove \r\n
            Serial.println((String)"Projector current state is '" + ProjectorPowerState + "'");
        }

        // now we are ready to control the projector and screen
        if (ProjectorPowerState == "OK0") {
            Serial.println("The projector is OFF now. We need to check the screen state");
            
            if (ProjectorPreviousPowerState == "OK1") { // we need to pull up the screen
                Serial.println("The projector was powered off, we need to pull up the screen");
                ScreenControl(UP);  // pull up the screen
                delay(PullUpTime);  // we need to wait a few seconds while screen will be pulled up
            }
            else {
                Serial.println((String)"Previous projector power state was '" + ProjectorPreviousPowerState + "', nothing to do");
            }
            ProjectorPreviousPowerState = ProjectorPowerState;

            //if projector is OFF, but the trigger is ON, we need to power on the projector
            if (voltage > (TriggerHigh*100)) {
                Serial.println("Trigger is ON now, so we need to power on the projector too");
                Serial1.print("~0000 1\r"); //power on
            }

        }
        else if (ProjectorPowerState == "OK1") {
            Serial.println("The projector is ON now. We need to check the screen state"); 

            if (ProjectorPreviousPowerState == "OK0") { // we need to push down the screen
                Serial.println("The projector was powered off, we need to push down the screen");
                ScreenControl(DOWN);  // push down the screen
                delay(PushDownTime);  // wait for a proper length
                ScreenControl(STOP);  // and stop
            }
            else {
                Serial.println((String)"Previous projector power state was '" + ProjectorPreviousPowerState + "', nothing to do");
            }
            ProjectorPreviousPowerState = ProjectorPowerState;

            //if projector is ON, but the trigger is OFF
            if (voltage < (TriggerLow*100)) {
                Serial.println("Trigger is off, so we need to power off the projector too");
                Serial1.print("~0000 0\r"); //power off
            }
        }
        else {
            Serial.println("The projector state is Unknown. Nothing to do");
        }
    }
    else {
        Serial.println("Projector serial connection is not available");
    }

    //initial request to projector, if it not send anything
    Serial1.print("~00124 1\r"); // powerstate query. OK0 if powered down, OK1 if powered on
    Serial.println("");
    delay(1000);
}
void recvWithEndMarker() { //thanks to https://forum.arduino.cc/t/problem-sending-serial-commands-to-a-video-projector/481406/4
    static byte ndx = 0;
    char endMarker = '\r';
    char rc;

    while (Serial1.available() > 0 && newData == false) {
        rc = Serial1.read();
        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
        }
    }
}
void ScreenControl(int Direction) {
    digitalWrite(EN,LOW); // Activate the multiplexer

    switch (Direction) {
        case 0: // multiplexer channel C0 
            Serial.println("Mode: STOP");
            digitalWrite(S0,LOW);
            digitalWrite(S1,LOW);
            digitalWrite(S2,LOW);
            digitalWrite(S3,LOW);
            break;
        case 1: // multiplexer channel C1 
            Serial.println("Mode: DOWN");
            digitalWrite(S0,HIGH);
            digitalWrite(S1,LOW);
            digitalWrite(S2,LOW);
            digitalWrite(S3,LOW);
            break;   
        case 2: // multiplexer channel C2  
            Serial.println("Mode: UP");
            digitalWrite(S0,LOW);
            digitalWrite(S1,HIGH);
            digitalWrite(S2,LOW);
            digitalWrite(S3,LOW);
            break;         
    }

    delay(100); 
    digitalWrite(EN, HIGH); //reset the multiplexer
}

void loop() {
}
#include <linux/uinput.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>
#include <jni.h>

int uinput;

extern "C"
JNIEXPORT void JNICALL
Java_com_monobogdan_inputservicebridge_InputNative_init(JNIEnv *env, jclass clazz) {
    uinput = open("/dev/input/event2", O_WRONLY);

    __android_log_print(ANDROID_LOG_DEBUG  , "Test", uinput >= 0 ? "Open event OK" : "Failed to open event");
}

void emit(int fd, int type, int code, int val)
{
    struct input_event ie;
    ie.type = type;
    ie.code = code;
    ie.value = val;
    /* timestamp values below are ignored */
    ie.time.tv_sec = 0;
    ie.time.tv_usec = 0;
    write(fd, &ie, sizeof(ie));
}

extern "C"
JNIEXPORT void JNICALL
Java_com_monobogdan_inputservicebridge_InputNative_sendKeyEvent(JNIEnv *env, jclass clazz,
                                                                jint key_code, jboolean pressed) {
    __android_log_print(ANDROID_LOG_DEBUG  , "Test", "Send");
    emit(uinput, EV_KEY, key_code, (bool)pressed  ? 1 : 0);
    emit(uinput, EV_SYN, SYN_REPORT, 0);
}package com.monobogdan.inputservicebridge;

public class InputListener extends Service {

    private static final int tty = 3;

    private InputManager iManager;
    private Map<Character, Integer> keyMap;
    private Method injectMethod;

    private Process runAsRoot(String cmd)
    {
        try {
            return Runtime.getRuntime().exec(new String[] { "su", "-c", cmd });
        }
        catch (IOException e)
        {
            e.printStackTrace();

            return null;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();

        // According to linux key map (input-event-codes.h)
        keyMap = new HashMap<>();
        keyMap.put('U', 103);
        keyMap.put('D', 108);
        keyMap.put('L', 105);
        keyMap.put('R', 106);
        keyMap.put('E', 115);
        keyMap.put('B', 158);
        keyMap.put('A', 232);
        keyMap.put('C', 212);

        InputNative.init();

        try {
            runAsRoot("chmod 777 /dev/input/event2").waitFor();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        Executors.newSingleThreadExecutor().execute(new Runnable() {
            @Override
            public void run() {
                Process proc = runAsRoot("cat /dev/ttyMT" + tty);
                BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));

                while(true)
                {
                    try {
                        String line = reader.readLine();

                        if(line != null && line.length() > 0) {
                            Log.i("Hi", "run: " + line);

                            boolean pressing = line.charAt(0) == 'D';
                            int keyCode = keyMap.get(line.charAt(2));

                            Log.i("TAG", "run: " + keyCode);
                            InputNative.sendKeyEvent(keyCode, pressing);
                        }
                    }
                    catch(IOException e)
                    {
                        e.printStackTrace();
                    }

                    /*try {
                        Thread.sleep(1000 / 30);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }*/
                }
            }
        });
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/time.h"
#include "hardware/uart.h"

struct keyMap
{
    int gpio;
    char key;
    bool pressed;
    int lastTick;
};

keyMap keys[] = {
    {
        15,
        'L',
        false,
        0
    },
    {
        14,
        'U',
        false,
        0
    },
    {
        13,
        'D',
        false,
        0
    },
    {
        12,
        'R',
        false,
        0
    },
    {
        11,
        'E',
        false,
        0
    },
    {
        10,
        'B',
        false,
        0
    },

    {
        20,
        'A',
        false,
        0
    },
    {
        21,
        'C',
        false,
        0
    }
};

#define KEY_NUM 8

int main() {
    stdio_init_all();

    uart_init(uart0, 921600);
    gpio_set_function(PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART);
    gpio_set_function(PICO_DEFAULT_UART_RX_PIN, GPIO_FUNC_UART);
    sleep_ms(1000); // Allow serial monitor to settle

    for(int i = 0; i <  KEY_NUM; i++)
    {
        gpio_init(keys[i].gpio);
        gpio_set_dir(keys[i].gpio, false);
        gpio_pull_up(keys[i].gpio);
    }

    while(true)
    {
        int now = time_us_32();

        for(int i = 0; i < KEY_NUM; i++)
        {
            char buf[5];
            buf[1] = ' ';
            buf[3] = '\n';
            buf[4] = 0;

            if(!gpio_get(keys[i].gpio) && !keys[i].pressed && now - keys[i].lastTick > 15500)
            {
                buf[0] = 'D';
                buf[2] = keys[i].key;
                puts(buf);

                keys[i].lastTick = now;
                keys[i].pressed = true;
                continue;
            }

            if(gpio_get(keys[i].gpio) && keys[i].pressed && now - keys[i].lastTick > 15500)
            {
                buf[0] = 'U';
                buf[2] = keys[i].key;
                puts(buf);

                keys[i].pressed = false;
                keys[i].lastTick = now;
            }

Credits

Jay Jordison

Jay Jordison

3 projects • 0 followers

Comments