【android】USBセレクターの制御 ~wifi経由~


 inkscapeを使って、ボタンのデザイン(( ..)φ)カキカキ

久々に触るのとバージョンがかなり前0.9台から1.4にしたこともあって、事前にクマを書いてしまった(チュートリアルをさらりとやって基本の操作を再度勉強)・・・https://inkscape.eksd.jp/

それなりにかっこいい?ボタンの画像イメージを作ってみた。PC1とPC2の2種類。
作成したファイルをPNGで保存。buttonpc1.pngとbuttonpc2.pngのファイル名で保存。

Android studioのimagebuttonの画像に割り当ててみる。新規プロジェクトを起こして、buttonpc1.pngとbuttonpc2.pn
のファイルをdrawableのフォルダーの下に移動させる。

その後、acrivity_main.xmlを編集、imagebuttonを2つ配置。
drawableにコピーした画像を割り当てる。普通に割り当てると、グレーの枠がついてしまう。

この背景を透明にしてやると、思い通りにはなるものの、一つ課題が、それはクリック感がなくなってしまう。
OC techNoteさんのHPに解決法があったので使わせていただく。

drawableのフォルダーに、image_button_bg.xmlをつくり
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true"
android:drawable="@color/black" />
</selector>
を記述する。
各ボタンのbuckgoundにこのxmlファイルを指定してあげるとクリックしたときに一瞬バックグランドの色が変わる。画像を用意しておいて、それに入れ替えてもOKなはず。まずまずは簡単なバックグランドの色を変更で。

最初は、有線接続でいいや!と思っていたのでusb-serial-for-androidの使い方とか勉強したんだが、結果、AVRのマイコンあらため、ESPのマイコンに鞍替えて、wifi経由で制御。

Wifi接続するためにAndroidManifest.xmlに
<uses-permission android:name="android.permission.INTERNET" />
を追加。
MainActivity.javaのファイルは以下のような感じ。
package com.example.myremocon1;

import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;

public class MainActivity extends AppCompatActivity {

private static Socket s;
private static PrintWriter printWriter;
String message="";
private static String ip="192.168.1.26";
private static int port=5000;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
}

public void send_text1(View v)
{
message="1";
myTask mt =new myTask();
mt.execute();
CharSequence text = "Setting to PC1!";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(this /* MyActivity */, text, duration);
toast.show();
}
public void send_text2(View v)
{
message="2";
myTask mt =new myTask();
mt.execute();
CharSequence text = "Setting to PC2!";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(this /* MyActivity */, text, duration);
toast.show();
}


class myTask extends AsyncTask<Void,Void,Void> {
protected Void doInBackground(Void... voids) {
try {
s=new Socket(ip,5000);
printWriter=new PrintWriter(s.getOutputStream());
printWriter.write(message);
printWriter.flush();
printWriter.close();
s.close();

}catch (IOException e){
e.printStackTrace();
}
簡単に、

onClickで呼び出させる関数にsend_text1をPC1のボタンに、send_text2をPC2のボタンにそれぞれ上のように関数を指定。

受信する側(サーバー側)はAruino IDEで以下のような簡単なものを作成。
#include <ESP8266WiFi.h>
#include <WiFiClient.h>

const char *ssid = "ssid";
const char *password = "password";
int usb_state;

WiFiServer server(5000);

void connectToWiFi() {
  WiFi.begin(ssid, password);
 // WiFi.setSleep(false); // WiFiスリープを無効にする


  // WiFi接続が確立されるまで待機
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
   // WiFi接続が確立した場合の処理
  String ip = WiFi.localIP().toString().c_str();

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.printf("IP Address  : ");
  Serial.println(WiFi.localIP());
   //サーバー立ち上げ
  server.begin();
  Serial.println("server.begin()");
  Serial.println(WiFi.macAddress());
}

bool timeout(WiFiClient client){
  int waitloops = 0;
  while (!client.available()){
    waitloops++;
    delay(1); //delay 1 msec
    if( 10000 < waitloops ){
      return true;
    }
  }
  return false;
}

void change_usb_channel(){
   digitalWrite(LED_BUILTIN, HIGH);   // push button on.
  delay(100);                      // Wait for a second
  digitalWrite(LED_BUILTIN, LOW);  
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);     // Initialize the LED_BUILTIN pin as an output
  pinMode(10, INPUT);     // readiing status of USB selector
  connectToWiFi();

  // Read status of USB selector
  digitalWrite(LED_BUILTIN, LOW);  
  int usb_state = digitalRead(10);
  if (usb_state==1){
     Serial.println( "USB channel == 1" );
  }else if (usb_state==0){
     Serial.println( "USB channel == 2" );
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  WiFiClient client = server.available();

  if (client) {
    Serial.println("New Client.");
    while (client.connected()) {
      //if( timeout(client) ) break;
      int size = client.available();
      if (size) {
        Serial.println();
        Serial.print("size:");
        Serial.println(size);

        char cmd[size + 1];  // command
        memset(cmd, 0, sizeof( cmd ));
        client.read( ( uint8_t* )cmd, size);
        cmd[size] = '\0';  // Add null terminator
        Serial.println( cmd );
       
        if( strcmp( cmd, "1" ) == 0 ){
          Serial.println( "receive 1" );
            if (usb_state==1){
              change_usb_channel();
              usb_state=1;
            }
           
          client.stop();
         }
        else if( strcmp( cmd, "2" ) == 0 ){
          Serial.println( "receive 2" );
            if (usb_state==0){
              change_usb_channel();
              usb_state=0;
            }
          client.stop();
          //赤外線送信
         
        }else if( strcmp( cmd, "3" ) == 0 ){
          Serial.println( "receive 3" );

          client.stop();      
        }
       
      }

      delay(1);
    }
    client.stop();
    Serial.println();
    Serial.println("client.stop()");
  }
  if (WiFi.status() != WL_CONNECTED) {
      connectToWiFi();
  }
  delay(1);
}


コマンドとして単に数字を受け取るだけ。数字3は用意しているが今回は受信しても何もしない。
回路の方は、ブレッドボードに前に作ったのそのまま。https://funasover.blogspot.com/2025/02/iotusbiot.html

実機のタブレットで試してみる。


USBセレクタが初期状態で1の状態になっていて、タブレットのPC2のボタンを押すと、USBセレクタが2に変更。続けて、タブレットのPC1のボタンを押すと、再度USBセレクタが1に。

少しバグがまだあって、

ボタンを押して、クライアントはサーバーに接続しにいくが、受信が確認できず・・という事がたまに?結構な頻度で起こる。

Arduinoのシリアル通信の内容を見ている限り、クライアントが接続しに行っているので、ソケット接続ができている事がわかる。しかし、次のメッセージが受け取れず、ソケットをそのままクローズしている。
その場対処だが少し、ソケット接続してから、メッセージを送り込むまでSleepさせてやった。下の箇所にSleep(50);を挿入。(かかわるインポートも実施)
class myTask extends AsyncTask<Void,Void,Void> {
protected Void doInBackground(Void... voids) {
try {
s=new Socket(ip,5000);
printWriter=new PrintWriter(s.getOutputStream());
sleep(50);
printWriter.write(message);
printWriter.flush();
printWriter.close();
s.close();
}catch (IOException e){
e.printStackTrace();
}
return null;
}
}
これで様子を見ているが、欠損はしておらず、ボタンを押すたびに、USBセレクターが確実に切り替わるようになった。
次回は、PC1とPC2にそれぞれHDMIのセレクターを連動させる事を試みることにする。















コメント

このブログの人気の投稿

Attiny85とAQM0802A(LCD)のI2C接続

ILI9341 240X320 Arduino