Отправить данные на последовательный порт, когда данные доступны - PullRequest
0 голосов
/ 13 мая 2019

Я строю интерактивный светодиодный стол с матрицей 14x14, состоящей из адресуемых светодиодных лент, для университетского задания.Они управляются двумя ардуино, которые получают данные о том, какой светодиод должен иметь значение RGB от Pi, на котором запущен сервер, на котором запущено несколько игр, которые должны быть доступны для игры на столе светодиодов.Для управления играми я отправляю соответствующие коды int из приложения для Android на сервер, работающий на Raspi.

Последовательная связь осуществляется с помощью jSerialComm.Проблема, с которой я сталкиваюсь, заключается в том, что я не хочу постоянно отправлять данные через последовательный порт, а только в тот момент, когда доступен новый массив, который задает матрицу.

Поэтому я не делаюхочу быть занятым ожиданием и постоянной проверкой, не обновилась ли матрица, не хочу ли я проверить наличие обновлений с

    while(!matrixUpdated) {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {}
    }

Так что я пытался запустить некоторое время (true), в котором я вызываюwait (), поэтому поток останавливается до тех пор, пока я не разбуду его, вызвав уведомление, когда обновленная матрица станет доступной.

Мой метод run () в последовательном потоке выглядит следующим образом:

@Override
public void run() {
    arduino1.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0);
    arduino2.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0);

    try {
        Thread.sleep(100);
    } catch (Exception e) {}

    PrintWriter outToArduino1 = new PrintWriter(arduino1.getOutputStream());
    PrintWriter outToArduino2 = new PrintWriter(arduino2.getOutputStream());

    while(true) {

        try {
            wait();
        } catch (InterruptedException e) {}

        System.out.println("Matrix received");

        outToArduino1.print(matrix);
        outToArduino2.print(matrix);
    }
}

Я пробуждаю поток этим методом, который вложен в тот же класс:

public void setMatrix(int[][][] pixelIdentifier) {
    matrix = pixelIdentifier;
    notify();
}

Я также попытался notifyAll (), который не изменил результат.

В одной из игр (Tic Tac Toe) я вызываю этот метод после каждого игрового хода, чтобы обновить и отправить матрицу в arduinos:

private void promptToMatrix() {
    synchronized (GameCenter.serialConnection) {
        GameCenter.serialConnection.setMatrix(matrix);
    }
}

Я ранее вызывал ее, не используя синхронизированный блок, но, как ячитал тИз многих статей на эту тему в StackOverflow я прочитал, что для этого нужно использовать синхронизированный.Кроме того, я также прочитал, что использование wait () и notify () не рекомендуется, однако, поскольку назначение должно быть выполнено довольно быстро, я не знаю, имеет ли смысл какой-либо другой подход, так как я не хочу реструктурировать все приложениетак как я запускаю до 5 потоков во время игры (из-за потоков для общения и т. д.).

Если есть возможность решить эту проблему с помощью wait () и notify (), я был бы действительноЯ рад услышать, как это будет сделано, так как я не смог по-настоящему понять, как правильно работает синхронный блок и так далее.Однако, если такое решение не возможно или также закончится реструктуризацией всего приложения, я также открыт для различных предложений.Указание на то, что использование wait () и notify () не рекомендуется, однако, не помогает мне, поскольку я уже читал это достаточно часто, я знаю об этом, но предпочитаю использовать его в этом случае, если это возможно !!!

РЕДАКТИРОВАТЬ:

The application executes like this: 
Main Thread
|--> SerialCommunication Thread --> waiting for updated data
|--> NetworkController Thread
     |--> Client Thread --> interacting with the game thread
          |--> Game Thread --> sending updated data to the waiting SerialCommunication Thread

Очень признателен за любую помощь и заранее спасибо за ваше время!

1 Ответ

0 голосов
/ 13 мая 2019

Вы имеете дело с асинхронным обновлением, возможно, работающим в разных потоках, на мой взгляд, наилучшим соответствием будет использование RxJava .

. Вы можете использовать Subject для получения матричного события, а затемподписаться на него, чтобы обновить светодиоды.

Вы можете написать что-то вроде этого (не воспринимайте это слишком буквально).

    public static void main(String[] args) {
        int[][] initialValue = new int[32][32];

        BehaviorSubject<int[][]> matrixSubject = BehaviorSubject.createDefault(initialValue);

        SerialPort arduino1 = initSerial("COM1");
        SerialPort arduino2 = initSerial("COM2");;

        PrintWriter outToArduino1 = new PrintWriter(arduino1.getOutputStream());
        PrintWriter outToArduino2 = new PrintWriter(arduino2.getOutputStream());

        Observable<String> serializedMatrix = matrixSubject.map(Sample::toChars);

        serializedMatrix.observeOn(Schedulers.io()).subscribe(mat -> {
            // Will run on a newly created thread  
            outToArduino1.println(mat);
        });

        serializedMatrix.observeOn(Schedulers.io()).subscribe(mat -> {
            // Will run on a newly created thread 
            outToArduino2.println(mat);
        });

        // Wait forever
        while(true) {
            try {
                // get your matrix somehow ...
                // then publish it on your subject
                // your subscribers will receive the data and use it.
                matrixSubject.onNext(matrix);
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // SWALLOW error
            }
        }

    }

    public static String toChars(int[][] data) {
        // Serialize data
        return null;
    }

Есть операторы may, которые вы могли бы использовать, чтобы сделать этоделать то, что вам нужно, также вы можете использовать разные планировщики для выбора из различных политик потоков.

Вы также можете преобразовать свой вход в тему, которую вы публикуете, наблюдаемый или тема может быть создана непосредственно из вашего ввода.

...