diff --git a/android-example/app/src/main/java/net/irext/ircontrol/controller/ArduinoControlCommand.java b/android-example/app/src/main/java/net/irext/ircontrol/controller/ArduinoControlCommand.java
deleted file mode 100644
index 374cc8b..0000000
--- a/android-example/app/src/main/java/net/irext/ircontrol/controller/ArduinoControlCommand.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package net.irext.ircontrol.controller;
-
-import com.google.gson.Gson;
-import net.irext.decode.sdk.bean.ACStatus;
-import net.irext.ircontrol.controller.base.ControlCommand;
-import org.jspecify.annotations.NonNull;
-
-import java.util.Base64;
-
-/**
- * Filename: ControlCommand.java
- * Revised: Date: 2026-01-22
- * Revision: Revision: 1.0
- *
- * Description: Remote command to Arduino remote
- *
- * Revision log:
- * 2026-01-22: created by strawmanbobi
- */
-public class ArduinoControlCommand extends ControlCommand {
-
- public ArduinoControlCommand(int keyCode, ACStatus acStatus) {
- this.keyCode = keyCode;
- this.acStatus = acStatus;
- }
-
- public ArduinoControlCommand() {
- }
-
- public int getKeyCode() {
- return keyCode;
- }
-
- public void setKeyCode(int keyCode) {
- this.keyCode = keyCode;
- }
-
- public ACStatus getAcStatus() {
- return acStatus;
- }
-
- public void setAcStatus(ACStatus acStatus) {
- this.acStatus = acStatus;
- }
-
- @Override
- public @NonNull String toString() {
- String jsonStr = new Gson().toJson(this);
- return Base64.getEncoder().encodeToString(jsonStr.getBytes());
- }
-}
diff --git a/android-example/app/src/main/java/net/irext/ircontrol/controller/ArduinoRemote.java b/android-example/app/src/main/java/net/irext/ircontrol/controller/ArduinoRemote.java
index 0b14b91..1fcafcd 100644
--- a/android-example/app/src/main/java/net/irext/ircontrol/controller/ArduinoRemote.java
+++ b/android-example/app/src/main/java/net/irext/ircontrol/controller/ArduinoRemote.java
@@ -2,35 +2,218 @@ package net.irext.ircontrol.controller;
import android.content.Context;
import android.util.Log;
+import com.google.gson.Gson;
import net.irext.decode.sdk.bean.ACStatus;
-import net.irext.ircontrol.controller.base.IRemote;
+import net.irext.ircontrol.controller.base.ControlCommand;
+import net.irext.ircontrol.controller.base.ControlHelper;
+import net.irext.ircontrol.controller.base.Remote;
+import org.jspecify.annotations.NonNull;
-import static net.irext.ircontrol.controller.ArduinoSocket.*;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.Socket;
+import java.util.Base64;
/**
* Filename: ArduinoRemote.java
* Revised: Date: 2026-01-18
* Revision: Revision: 1.0
*
- * Description: Remote implementation by Arduino
+ * Description: Communication interface to Arduino
*
* Revision log:
*2026-01-18: created by strawmanbobi
*/
-public class ArduinoRemote implements IRemote {
-
+public class ArduinoRemote extends Remote {
private static final String TAG = ArduinoRemote.class.getSimpleName();
- Context mContext;
- ArduinoSocket mArduinoSocket;
+ public static final int EMITTER_DISCONNECTED = 0;
+ public static final int EMITTER_CONNECTED = 1;
+ public static final int EMITTER_WORKING = 2;
- public ArduinoRemote(Context context, ArduinoSocket socket) {
- mContext = context;
- mArduinoSocket = socket;
+ public static final int EMITTER_PORT = 8000;
+
+ public static final String A_REQUEST_HELLO = "a_hello";
+ public static final String E_RESPONSE_HELLO = "e_hello";
+
+ public static final String A_REQUEST_BIN = "a_bin";
+ public static final String E_RESPONSE_BIN = "e_bin";
+
+ public static final String A_REQUEST_CTRL = "a_control";
+ public static final String E_RESPONSE_CTRL = "e_control";
+
+ private Socket emitterConn = null;
+ private int connectionStatus = EMITTER_DISCONNECTED;
+ private IRSocketEmitterCallback callback;
+
+ private Context mContext = null;
+
+ private static ArduinoRemote mInstance;
+
+ public static ArduinoRemote getInstance(Context context, IRSocketEmitterCallback callback) {
+ if (mInstance == null) {
+ mInstance = new ArduinoRemote(context, callback);
+ }
+ return mInstance;
}
- @Override
- public int irControl(int category, int subCategory, int keyCode) {
+ public Context getContext() {
+ return mContext;
+ }
+
+ public void setContext(Context mContext) {
+ this.mContext = mContext;
+ }
+
+ public interface IRSocketEmitterCallback {
+ void onConnected();
+ void onDisconnected();
+ void onResponse(String response);
+ }
+
+ public ArduinoRemote(Context context, IRSocketEmitterCallback callback) {
+ this.mContext = context;
+ this.callback = callback;
+ }
+
+ public void setCallback(IRSocketEmitterCallback callback) {
+ this.callback = callback;
+ }
+
+ public int getConnectionStatus() {
+ return connectionStatus;
+ }
+
+ public void connectToEmitter(String ipAddress, String port) {
+ if (connectionStatus == EMITTER_DISCONNECTED) {
+ if (ipAddress == null || port == null) {
+ return;
+ }
+ new Thread(() -> {
+ try {
+ emitterConn = new Socket(ipAddress, Integer.parseInt(port));
+ emitterConn.setKeepAlive(true);
+ connectionStatus = EMITTER_CONNECTED;
+
+ onConnected();
+
+ BufferedReader in = new BufferedReader(new InputStreamReader(emitterConn.getInputStream()));
+ String response;
+ while ((response = in.readLine()) != null) {
+ onResponse(response);
+ }
+
+ if (callback != null) {
+ callback.onDisconnected();
+ }
+
+ connectionStatus = EMITTER_DISCONNECTED;
+ } catch (IOException ioException) {
+ Log.e(TAG, "Connection error: " + ioException.getMessage());
+
+ if (callback != null) {
+ callback.onDisconnected();
+ }
+
+ connectionStatus = EMITTER_DISCONNECTED;
+ }
+ }).start();
+ } else {
+ disconnect();
+ }
+ }
+
+ public void disconnect() {
+ try {
+ if (emitterConn != null && !emitterConn.isClosed()) {
+ emitterConn.close();
+ }
+ connectionStatus = EMITTER_DISCONNECTED;
+ } catch (IOException e) {
+ Log.e(TAG, "Error closing connection: " + e.getMessage());
+ }
+ }
+
+ public void sendHelloToEmitter() {
+ new Thread(() -> {
+ try {
+ Log.d(TAG, "sending a_hello to emitter");
+ PrintWriter out = new PrintWriter(emitterConn.getOutputStream(), true);
+ out.println(A_REQUEST_HELLO);
+ } catch (IOException e) {
+ Log.e(TAG, "Error sending hello: " + e.getMessage());
+ }
+ }).start();
+ }
+
+ public void sendBinToEmitter(byte[] binContent, int categoryId, int subCate) {
+ if (binContent == null) {
+ Log.e(TAG, "binary bytes is null");
+ return;
+ }
+ String binBase64 = Base64.getEncoder().encodeToString(binContent);
+ String binStr = A_REQUEST_BIN + "," + categoryId + "," + subCate + "," + binBase64.length() + "," + binBase64;
+ Log.d(TAG, "sending bin in base64: " + binStr);
+ new Thread(() -> {
+ try {
+ PrintWriter out = new PrintWriter(emitterConn.getOutputStream(), true);
+ out.println(binStr);
+ } catch (Exception e) {
+ Log.e(TAG, "Error sending binary data: " + e.getMessage());
+ }
+ }).start();
+ }
+
+ public void sendControlToEmitter(String command) {
+
+ String commandStr = A_REQUEST_CTRL + "," + command.length() + "," + command;
+
+ Log.d(TAG, "sending command in base64: " + commandStr);
+ new Thread(() -> {
+ try {
+ PrintWriter out = new PrintWriter(emitterConn.getOutputStream(), true);
+ out.println(commandStr);
+ } catch (IOException e) {
+ Log.e(TAG, "Error sending control data: " + e.getMessage());
+ }
+ }).start();
+ }
+
+ public void sendDecodedToEmitter(String binContent) {
+ new Thread(() -> {
+ try {
+ PrintWriter out = new PrintWriter(emitterConn.getOutputStream(), true);
+ out.println(binContent);
+ } catch (IOException e) {
+ Log.e(TAG, "Error sending decoded data: " + e.getMessage());
+ }
+ }).start();
+ }
+
+ private void onConnected() {
+ if (callback != null) {
+ Log.d(TAG, "the emitter is connected");
+ callback.onConnected();
+ }
+ }
+
+ private void onResponse(String response) {
+ if (response.startsWith(ArduinoRemote.E_RESPONSE_HELLO)) {
+ Log.d(TAG, "received e_hello");
+ } else if (response.startsWith(ArduinoRemote.E_RESPONSE_BIN)) {
+ Log.d(TAG, "received e_bin");
+ } else if (response.startsWith(ArduinoRemote.E_RESPONSE_CTRL)) {
+ connectionStatus = EMITTER_WORKING;
+ } else {
+ Log.e(TAG, "unexpected response : " + response);
+ }
+ callback.onResponse(response);
+ }
+
+
+ public void irControl(int category, int subCategory, int keyCode) {
Log.d(TAG, "irControl, category = " + category + ", subCategory = " + subCategory + ", keyCode = " + keyCode);
@@ -40,8 +223,40 @@ public class ArduinoRemote implements IRemote {
ArduinoControlCommand command = new ArduinoControlCommand(inputKeyCode, acStatus);
String controlCommand = command.toString();
- mArduinoSocket.sendControlToEmitter(controlCommand);
+ sendControlToEmitter(controlCommand);
- return 0;
}
-}
+
+ private static class ArduinoControlCommand extends ControlCommand {
+
+ public ArduinoControlCommand(int keyCode, ACStatus acStatus) {
+ this.keyCode = keyCode;
+ this.acStatus = acStatus;
+ }
+
+ public ArduinoControlCommand() {
+ }
+
+ public int getKeyCode() {
+ return keyCode;
+ }
+
+ public void setKeyCode(int keyCode) {
+ this.keyCode = keyCode;
+ }
+
+ public ACStatus getAcStatus() {
+ return acStatus;
+ }
+
+ public void setAcStatus(ACStatus acStatus) {
+ this.acStatus = acStatus;
+ }
+
+ @Override
+ public @NonNull String toString() {
+ String jsonStr = new Gson().toJson(this);
+ return Base64.getEncoder().encodeToString(jsonStr.getBytes());
+ }
+ }
+}
\ No newline at end of file
diff --git a/android-example/app/src/main/java/net/irext/ircontrol/controller/ArduinoSocket.java b/android-example/app/src/main/java/net/irext/ircontrol/controller/ArduinoSocket.java
deleted file mode 100644
index a461577..0000000
--- a/android-example/app/src/main/java/net/irext/ircontrol/controller/ArduinoSocket.java
+++ /dev/null
@@ -1,188 +0,0 @@
-package net.irext.ircontrol.controller;
-
-import android.util.Log;
-import android.util.Patterns;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.net.Socket;
-import java.util.Base64;
-
-/**
- * Filename: ArduinoSocket.java
- * Revised: Date: 2026-01-18
- * Revision: Revision: 1.0
- *
- * Description: Communication interface to Arduino
- *
- * Revision log:
- *2026-01-18: created by strawmanbobi
- */
-public class ArduinoSocket {
- private static final String TAG = ArduinoSocket.class.getSimpleName();
-
- public static final int EMITTER_DISCONNECTED = 0;
- public static final int EMITTER_CONNECTED = 1;
- public static final int EMITTER_WORKING = 2;
-
- public static final int EMITTER_PORT = 8000;
-
- public static final String A_REQUEST_HELLO = "a_hello";
- public static final String E_RESPONSE_HELLO = "e_hello";
-
- public static final String A_REQUEST_BIN = "a_bin";
- public static final String E_RESPONSE_BIN = "e_bin";
-
- public static final String A_REQUEST_CTRL = "a_control";
- public static final String E_RESPONSE_CTRL = "e_control";
-
- private Socket emitterConn = null;
- private int connectionStatus = EMITTER_DISCONNECTED;
- private IRSocketEmitterCallback callback;
-
- public interface IRSocketEmitterCallback {
- void onConnected();
- void onDisconnected();
- void onResponse(String response);
- }
-
- public ArduinoSocket(IRSocketEmitterCallback callback) {
- this.callback = callback;
- }
-
- public void setCallback(IRSocketEmitterCallback callback) {
- this.callback = callback;
- }
-
- public int getConnectionStatus() {
- return connectionStatus;
- }
-
- public void connectToEmitter(String ipAddress, String port) {
- if (connectionStatus == EMITTER_DISCONNECTED) {
- if (ipAddress == null || port == null) {
- return;
- }
- new Thread(() -> {
- try {
- emitterConn = new Socket(ipAddress, Integer.parseInt(port));
- emitterConn.setKeepAlive(true);
- connectionStatus = EMITTER_CONNECTED;
-
- onConnected();
-
- BufferedReader in = new BufferedReader(new InputStreamReader(emitterConn.getInputStream()));
- String response;
- while ((response = in.readLine()) != null) {
- onResponse(response);
- }
-
- if (callback != null) {
- callback.onDisconnected();
- }
-
- connectionStatus = EMITTER_DISCONNECTED;
- } catch (IOException ioException) {
- Log.e(TAG, "Connection error: " + ioException.getMessage());
-
- if (callback != null) {
- callback.onDisconnected();
- }
-
- connectionStatus = EMITTER_DISCONNECTED;
- }
- }).start();
- } else {
- disconnect();
- }
- }
-
- public void disconnect() {
- try {
- if (emitterConn != null && !emitterConn.isClosed()) {
- emitterConn.close();
- }
- connectionStatus = EMITTER_DISCONNECTED;
- } catch (IOException e) {
- Log.e(TAG, "Error closing connection: " + e.getMessage());
- }
- }
-
- public void sendHelloToEmitter() {
- new Thread(() -> {
- try {
- Log.d(TAG, "sending a_hello to emitter");
- PrintWriter out = new PrintWriter(emitterConn.getOutputStream(), true);
- out.println(A_REQUEST_HELLO);
- } catch (IOException e) {
- Log.e(TAG, "Error sending hello: " + e.getMessage());
- }
- }).start();
- }
-
- public void sendBinToEmitter(byte[] binContent, int categoryId, int subCate) {
- if (binContent == null) {
- Log.e(TAG, "binary bytes is null");
- return;
- }
-
- String binBase64 = Base64.getEncoder().encodeToString(binContent);
- String binStr = A_REQUEST_BIN + "," + categoryId + "," + subCate + "," + binBase64.length() + "," + binBase64;
- Log.d(TAG, "sending bin in base64: " + binStr);
- new Thread(() -> {
- try {
- PrintWriter out = new PrintWriter(emitterConn.getOutputStream(), true);
- out.println(binStr);
- } catch (Exception e) {
- Log.e(TAG, "Error sending binary data: " + e.getMessage());
- }
- }).start();
- }
-
- public void sendControlToEmitter(String command) {
- String commandStr = A_REQUEST_CTRL + "," + command.length() + "," + command;
- Log.d(TAG, "sending command in base64: " + commandStr);
- new Thread(() -> {
- try {
- PrintWriter out = new PrintWriter(emitterConn.getOutputStream(), true);
- out.println(commandStr);
- } catch (IOException e) {
- Log.e(TAG, "Error sending control data: " + e.getMessage());
- }
- });
- }
-
- public void sendDecodedToEmitter(String binContent) {
- new Thread(() -> {
- try {
- PrintWriter out = new PrintWriter(emitterConn.getOutputStream(), true);
- out.println(binContent);
- } catch (IOException e) {
- Log.e(TAG, "Error sending decoded data: " + e.getMessage());
- }
- }).start();
- }
-
-
- private void onConnected() {
- if (callback != null) {
- Log.d(TAG, "the emitter is connected");
- callback.onConnected();
- }
- }
-
- private void onResponse(String response) {
- if (response.startsWith(ArduinoSocket.E_RESPONSE_HELLO)) {
- ;
- } else if (response.startsWith(ArduinoSocket.E_RESPONSE_BIN)) {
- ;
- } else if (response.startsWith(ArduinoSocket.E_RESPONSE_CTRL)) {
- connectionStatus = EMITTER_WORKING;
- } else {
- Log.e(TAG, "unexpected response : " + response);
- }
- callback.onResponse(response);
- }
-}
\ No newline at end of file
diff --git a/android-example/app/src/main/java/net/irext/ircontrol/controller/PhoneRemote.java b/android-example/app/src/main/java/net/irext/ircontrol/controller/PhoneRemote.java
index fc76ef0..e0f105f 100644
--- a/android-example/app/src/main/java/net/irext/ircontrol/controller/PhoneRemote.java
+++ b/android-example/app/src/main/java/net/irext/ircontrol/controller/PhoneRemote.java
@@ -4,7 +4,8 @@ import android.content.Context;
import android.util.Log;
import net.irext.decode.sdk.IRDecode;
import net.irext.decode.sdk.bean.ACStatus;
-import net.irext.ircontrol.controller.base.IRemote;
+import net.irext.ircontrol.controller.base.ControlHelper;
+import net.irext.ircontrol.controller.base.Remote;
/**
* Filename: PhoneRemote.java
@@ -16,19 +17,27 @@ import net.irext.ircontrol.controller.base.IRemote;
* Revision log:
*2026-01-18: created by strawmanbobi
*/
-public class PhoneRemote implements IRemote {
+public class PhoneRemote extends Remote {
private static final String TAG = PhoneRemote.class.getSimpleName();
- IRDecode mIRDecode;
+ private Context mContext;
+ private IRDecode mIRDecode;
+
+ private static PhoneRemote mInstance;
- Context mContext;
public PhoneRemote(Context context) {
mContext = context;
mIRDecode = new IRDecode();
}
- @Override
+ public static PhoneRemote getInstance(Context context) {
+ if (mInstance == null) {
+ mInstance = new PhoneRemote(context);
+ }
+ return mInstance;
+ }
+
public int irControl(int category, int subCategory, int keyCode) {
int []decoded;
StringBuilder debugStr = new StringBuilder();
diff --git a/android-example/app/src/main/java/net/irext/ircontrol/controller/ControlHelper.java b/android-example/app/src/main/java/net/irext/ircontrol/controller/base/ControlHelper.java
similarity index 97%
rename from android-example/app/src/main/java/net/irext/ircontrol/controller/ControlHelper.java
rename to android-example/app/src/main/java/net/irext/ircontrol/controller/base/ControlHelper.java
index 8e084d6..62737d4 100644
--- a/android-example/app/src/main/java/net/irext/ircontrol/controller/ControlHelper.java
+++ b/android-example/app/src/main/java/net/irext/ircontrol/controller/base/ControlHelper.java
@@ -1,4 +1,4 @@
-package net.irext.ircontrol.controller;
+package net.irext.ircontrol.controller.base;
import android.content.Context;
import android.hardware.ConsumerIrManager;
@@ -9,7 +9,7 @@ import net.irext.ircontrol.utils.ToastUtils;
import java.util.Objects;
-import static net.irext.ircontrol.controller.base.IRemote.*;
+import static net.irext.ircontrol.controller.base.Remote.*;
/**
* Filename: ControlHelper.java
diff --git a/android-example/app/src/main/java/net/irext/ircontrol/controller/base/IRemote.java b/android-example/app/src/main/java/net/irext/ircontrol/controller/base/Remote.java
similarity index 77%
rename from android-example/app/src/main/java/net/irext/ircontrol/controller/base/IRemote.java
rename to android-example/app/src/main/java/net/irext/ircontrol/controller/base/Remote.java
index a820535..0d73db3 100644
--- a/android-example/app/src/main/java/net/irext/ircontrol/controller/base/IRemote.java
+++ b/android-example/app/src/main/java/net/irext/ircontrol/controller/base/Remote.java
@@ -1,16 +1,16 @@
package net.irext.ircontrol.controller.base;
/**
- * Filename: IRemote.java
+ * Filename: Remote.java
* Revised: Date: 2026-01-18
* Revision: Revision: 1.0
*
- * Description: IRemote interface
+ * Description: Remote interface
*
* Revision log:
*2026-01-18: created by strawmanbobi
*/
-public interface IRemote {
+public abstract class Remote {
public static final int KEY_POWER = 0;
public static final int KEY_UP = 1;
@@ -24,6 +24,8 @@ public interface IRemote {
public static final int KEY_HOME = 9;
public static final int KEY_MENU = 10;
- int irControl(int category, int subCategory, int keyCode);
+ int irControl(int category, int subCategory, int keyCode) {
+ return 0;
+ }
}
diff --git a/android-example/app/src/main/java/net/irext/ircontrol/ui/fragment/ControlFragment.java b/android-example/app/src/main/java/net/irext/ircontrol/ui/fragment/ControlFragment.java
index d6e4e83..12f036e 100644
--- a/android-example/app/src/main/java/net/irext/ircontrol/ui/fragment/ControlFragment.java
+++ b/android-example/app/src/main/java/net/irext/ircontrol/ui/fragment/ControlFragment.java
@@ -3,6 +3,7 @@ package net.irext.ircontrol.ui.fragment;
import android.content.Context;
import android.graphics.Color;
import android.os.*;
+import android.provider.ContactsContract;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -15,9 +16,8 @@ import net.irext.decode.sdk.IRDecode;
import net.irext.ircontrol.R;
import net.irext.ircontrol.bean.RemoteControl;
import net.irext.ircontrol.controller.ArduinoRemote;
-import net.irext.ircontrol.controller.ArduinoSocket;
import net.irext.ircontrol.controller.PhoneRemote;
-import net.irext.ircontrol.controller.base.IRemote;
+import net.irext.ircontrol.controller.base.Remote;
import net.irext.ircontrol.ui.activity.ControlActivity;
import net.irext.ircontrol.utils.FileUtils;
import net.irext.ircontrol.utils.MessageUtils;
@@ -45,7 +45,8 @@ public class ControlFragment extends Fragment implements View.OnClickListener {
private static final int CMD_GET_REMOTE_CONTROL = 0;
- private ArduinoSocket mArduinoSocket;
+ private PhoneRemote mPhoneRemote;
+ private ArduinoRemote mArduinoRemote;
private MsgHandler mHandler;
@@ -96,12 +97,8 @@ public class ControlFragment extends Fragment implements View.OnClickListener {
btnPlus.setOnClickListener(this);
btnMinus.setOnClickListener(this);
- mEtEmitterIp = view.findViewById(R.id.emitter_ip);
- mBtnConnect = view.findViewById(R.id.btn_connect_emitter);
- mVWConnectStatus = view.findViewById(R.id.vw_connect_status);
-
- // Initialize ArduinoSocket with callback
- mArduinoSocket = new ArduinoSocket(new ArduinoSocket.IRSocketEmitterCallback() {
+ mPhoneRemote = PhoneRemote.getInstance(mParent);
+ mArduinoRemote = ArduinoRemote.getInstance(mParent, new ArduinoRemote.IRSocketEmitterCallback() {
@Override
public void onConnected() {
onEmitterConnected();
@@ -118,6 +115,10 @@ public class ControlFragment extends Fragment implements View.OnClickListener {
}
});
+ mEtEmitterIp = view.findViewById(R.id.emitter_ip);
+ mBtnConnect = view.findViewById(R.id.btn_connect_emitter);
+ mVWConnectStatus = view.findViewById(R.id.vw_connect_status);
+
mBtnConnect.setOnClickListener(new View.OnClickListener() {
@Override
@@ -129,7 +130,7 @@ public class ControlFragment extends Fragment implements View.OnClickListener {
ToastUtils.showToast(mParent, mParent.getString(R.string.input_emitter_ip_address), null);
return;
}
- mArduinoSocket.connectToEmitter(emitterIp, String.valueOf(ArduinoSocket.EMITTER_PORT));
+ mArduinoRemote.connectToEmitter(emitterIp, String.valueOf(ArduinoRemote.EMITTER_PORT));
}
});
@@ -152,13 +153,13 @@ public class ControlFragment extends Fragment implements View.OnClickListener {
@Override
public void onStop() {
super.onStop();
- mArduinoSocket.disconnect();
+ mArduinoRemote.disconnect();
}
@Override
public void onDestroyView() {
super.onDestroyView();
- mArduinoSocket.disconnect();
+ mArduinoRemote.disconnect();
}
private void getRemote() {
@@ -202,7 +203,7 @@ public class ControlFragment extends Fragment implements View.OnClickListener {
}
private void processEHello(String response) {
- mArduinoSocket.sendHelloToEmitter();
+ mArduinoRemote.sendHelloToEmitter();
}
private void processEBin(String response) {
@@ -210,7 +211,7 @@ public class ControlFragment extends Fragment implements View.OnClickListener {
mCurrentRemoteControl.getRemoteMap() + FileUtils.FILE_NAME_EXT;
byte []binContent = FileUtils.getByteArrayFromFile(binFileName);
if (null != binContent) {
- mArduinoSocket.sendBinToEmitter(binContent, mCurrentRemoteControl.getCategoryId(), mCurrentRemoteControl.getSubCategory());
+ mArduinoRemote.sendBinToEmitter(binContent, mCurrentRemoteControl.getCategoryId(), mCurrentRemoteControl.getSubCategory());
} else {
Log.e(TAG, "emitter sender could not open the binary file");
ToastUtils.showToast(mParent, mParent.getString(R.string.file_could_not_open), Toast.LENGTH_SHORT);
@@ -222,11 +223,11 @@ public class ControlFragment extends Fragment implements View.OnClickListener {
}
private void onEmitterResponse(String response) {
- if (response.startsWith(ArduinoSocket.E_RESPONSE_HELLO)) {
+ if (response.startsWith(ArduinoRemote.E_RESPONSE_HELLO)) {
processEHello(response);
- } else if (response.startsWith(ArduinoSocket.E_RESPONSE_BIN)) {
+ } else if (response.startsWith(ArduinoRemote.E_RESPONSE_BIN)) {
processEBin(response);
- } else if (response.startsWith(ArduinoSocket.E_RESPONSE_CTRL)) {
+ } else if (response.startsWith(ArduinoRemote.E_RESPONSE_CTRL)) {
processECtrl(response);
} else {
Log.e(TAG, "unexpected response : " + response);
@@ -237,39 +238,38 @@ public class ControlFragment extends Fragment implements View.OnClickListener {
@Override
public void onClick(View v) {
vibrate(mParent);
- IRemote remote = null;
+ Remote remote = null;
int keyCode = 0;
int id = v.getId();
if (id == R.id.iv_power) {
- keyCode = IRemote.KEY_POWER;
+ keyCode = Remote.KEY_POWER;
} else if (id == R.id.iv_up) {
- keyCode = IRemote.KEY_UP;
+ keyCode = Remote.KEY_UP;
} else if (id == R.id.iv_down) {
- keyCode = IRemote.KEY_DOWN;
+ keyCode = Remote.KEY_DOWN;
} else if (id == R.id.iv_left) {
- keyCode = IRemote.KEY_LEFT;
+ keyCode = Remote.KEY_LEFT;
} else if (id == R.id.iv_right) {
- keyCode = IRemote.KEY_RIGHT;
+ keyCode = Remote.KEY_RIGHT;
} else if (id == R.id.iv_ok) {
- keyCode = IRemote.KEY_OK;
+ keyCode = Remote.KEY_OK;
} else if (id == R.id.iv_plus) {
- keyCode = IRemote.KEY_PLUS;
+ keyCode = Remote.KEY_PLUS;
} else if (id == R.id.iv_minus) {
- keyCode = IRemote.KEY_MINUS;
+ keyCode = Remote.KEY_MINUS;
} else if (id == R.id.iv_back) {
- keyCode = IRemote.KEY_BACK;
+ keyCode = Remote.KEY_BACK;
} else if (id == R.id.iv_home) {
- keyCode = IRemote.KEY_HOME;
+ keyCode = Remote.KEY_HOME;
} else if (id == R.id.iv_menu) {
- keyCode = IRemote.KEY_MENU;
+ keyCode = Remote.KEY_MENU;
}
- if (mArduinoSocket.getConnectionStatus() == ArduinoSocket.EMITTER_WORKING) {
- remote = new ArduinoRemote(mParent, mArduinoSocket);
+ if (mArduinoRemote.getConnectionStatus() == ArduinoRemote.EMITTER_WORKING) {
+ mArduinoRemote.irControl(mCurrentRemoteControl.getCategoryId(), mCurrentRemoteControl.getSubCategory(), keyCode);
} else {
- remote = new PhoneRemote(mParent);
+ mPhoneRemote.irControl(mCurrentRemoteControl.getCategoryId(), mCurrentRemoteControl.getSubCategory(), keyCode);
}
- remote.irControl(mCurrentRemoteControl.getCategoryId(), mCurrentRemoteControl.getSubCategory(), keyCode);
}
private static class MsgHandler extends Handler {
diff --git a/arduino-example/platformio.ini b/arduino-example/platformio.ini
index eaa9f3a..510aa58 100644
--- a/arduino-example/platformio.ini
+++ b/arduino-example/platformio.ini
@@ -20,6 +20,9 @@ lib_deps =
ArduinoGraphics
Arduino_LED_Matrix
adamvr/base64@^1.0.0
+ ArduinoJson
+ IRremote
build_flags =
- -I ./src/ir_decode/include
\ No newline at end of file
+ -I ./src/ir_decode/include
+ -DBOARD_ARDUINO
\ No newline at end of file
diff --git a/arduino-example/src/configure.h b/arduino-example/src/configure.h
index 0d097e6..58f97a1 100644
--- a/arduino-example/src/configure.h
+++ b/arduino-example/src/configure.h
@@ -27,10 +27,12 @@
#include
// Wi-Fi Configs
-// #define SECRET_SSID "Maomao的小房子"
-// #define SECRET_PASS "Maomao121207"
-#define SECRET_SSID "maomao"
-#define SECRET_PASS "20121207"
+#define SECRET_SSID "Maomao的小房子"
+#define SECRET_PASS "Maomao121207"
+// #define SECRET_SSID "maomao"
+// #define SECRET_PASS "20121207"
+
+// #define TEST_BIN_RECEIVE (1)
// LED Matrix Definitions
constexpr uint32_t chip[] = {
diff --git a/arduino-example/src/control_command.cpp b/arduino-example/src/control_command.cpp
new file mode 100644
index 0000000..0f4a39c
--- /dev/null
+++ b/arduino-example/src/control_command.cpp
@@ -0,0 +1,66 @@
+/**
+*
+ * Copyright (c) 2020-2025 IRext Opensource Organization
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include
+
+#include "serial_log.h"
+#include "control_command.h"
+
+
+// public function definitions
+int parseControlCommand(int category, const char *commandJson,
+ t_remote_ac_status *ac_status, int* keyCode) {
+ JsonDocument doc;
+ DeserializationError error = deserializeJson(doc, commandJson);
+
+ if (error) {
+ serialPrint(LOG_ERROR, "Parsing command JSON failed: %s", error.c_str());
+ return -1;
+ }
+
+ // Parse AC status fields from JSON according to ACStatus structure
+ ac_status->ac_power = doc["acStatus"]["acPower"];
+ ac_status->ac_temp = doc["acStatus"]["acTemp"];
+ ac_status->ac_mode = doc["acStatus"]["acMode"];
+ ac_status->ac_wind_dir = doc["acStatus"]["acWindDir"];
+ ac_status->ac_wind_speed = doc["acStatus"]["acWindSpeed"];
+ ac_status->ac_display = doc["acStatus"]["acDisplay"];
+ ac_status->ac_sleep = doc["acStatus"]["acSleep"];
+ ac_status->ac_timer = doc["acStatus"]["acTimer"];
+ ac_status->change_wind_direction = doc["acStatus"]["changeWindDir"];
+ *keyCode = doc["keyCode"];
+
+ serialPrint(LOG_VERBOSE, "--- AC Status ---");
+ serialPrint(LOG_VERBOSE, "Power: %d", ac_status->ac_power);
+ serialPrint(LOG_VERBOSE, "Temperature: %d", ac_status->ac_temp);
+ serialPrint(LOG_VERBOSE, "Mode: %d", ac_status->ac_mode);
+ serialPrint(LOG_VERBOSE, "Wind Direction: %d", ac_status->ac_wind_dir);
+ serialPrint(LOG_VERBOSE, "Wind Speed: %d", ac_status->ac_wind_speed);
+ serialPrint(LOG_VERBOSE, "Display: %d", ac_status->ac_display);
+ serialPrint(LOG_VERBOSE, "Sleep: %d", ac_status->ac_sleep);
+ serialPrint(LOG_VERBOSE, "Timer: %d", ac_status->ac_timer);
+ serialPrint(LOG_VERBOSE, "Change Wind Direction: %d", ac_status->change_wind_direction);
+ serialPrint(LOG_VERBOSE, "Key Code: %d", *keyCode);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/arduino-example/src/control_command.h b/arduino-example/src/control_command.h
new file mode 100644
index 0000000..bb2a6dd
--- /dev/null
+++ b/arduino-example/src/control_command.h
@@ -0,0 +1,40 @@
+/**
+*
+ * Copyright (c) 2020-2025 IRext Opensource Organization
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef ARDUINO_EXAMPLE_CONTROL_COMMAND_H
+#define ARDUINO_EXAMPLE_CONTROL_COMMAND_H
+
+#include "ir_decode.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int parseControlCommand(int category, const char *commandJson,
+ t_remote_ac_status *ac_status, int* keyCode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // ARDUINO_EXAMPLE_CONTROL_COMMAND_H
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/include/ir_ac_apply.h b/arduino-example/src/ir_decode/include/ir_ac_apply.h
index af68831..4c149cf 100644
--- a/arduino-example/src/ir_decode/include/ir_ac_apply.h
+++ b/arduino-example/src/ir_decode/include/ir_ac_apply.h
@@ -26,15 +26,15 @@ extern "C"
#define MIN_TAG_LENGTH_TYPE_1 4
#define MIN_TAG_LENGTH_TYPE_2 6
-INT8 apply_power(t_remote_ac_status ac_status, UINT8 function_code);
+INT8 apply_power(t_remote_ac_status *ac_status, UINT8 function_code);
-INT8 apply_mode(t_remote_ac_status ac_status, UINT8 function_code);
+INT8 apply_mode(t_remote_ac_status *ac_status, UINT8 function_code);
-INT8 apply_wind_speed(t_remote_ac_status ac_status, UINT8 function_code);
+INT8 apply_wind_speed(t_remote_ac_status *ac_status, UINT8 function_code);
-INT8 apply_swing(t_remote_ac_status ac_status, UINT8 function_code);
+INT8 apply_swing(t_remote_ac_status *ac_status, UINT8 function_code);
-INT8 apply_temperature(t_remote_ac_status ac_status, UINT8 function_code);
+INT8 apply_temperature(t_remote_ac_status *ac_status, UINT8 function_code);
INT8 apply_function(struct ac_protocol *protocol, UINT8 function);
diff --git a/arduino-example/src/ir_decode/include/ir_ac_control.h b/arduino-example/src/ir_decode/include/ir_ac_control.h
index 68bf99f..16d8406 100644
--- a/arduino-example/src/ir_decode/include/ir_ac_control.h
+++ b/arduino-example/src/ir_decode/include/ir_ac_control.h
@@ -342,7 +342,7 @@ typedef struct ac_protocol
UINT8 swing_status;
- BOOL change_wind_direction;
+ UINT8 change_wind_direction;
UINT16 dc_cnt;
t_ac_bit_num bit_num[MAX_BITNUM];
@@ -382,10 +382,11 @@ typedef struct REMOTE_AC_STATUS
UINT8 ac_display;
UINT8 ac_sleep;
UINT8 ac_timer;
+ UINT8 change_wind_direction;
} t_remote_ac_status;
// function polymorphism
-typedef INT8 (*lp_apply_ac_parameter)(t_remote_ac_status ac_status, UINT8 function_code);
+typedef INT8 (*lp_apply_ac_parameter)(t_remote_ac_status *ac_status, UINT8 function_code);
#define TAG_AC_BOOT_CODE 1
#define TAG_AC_ZERO 2
diff --git a/arduino-example/src/ir_decode/include/ir_decode.h b/arduino-example/src/ir_decode/include/ir_decode.h
index 6d7ebeb..e237e41 100644
--- a/arduino-example/src/ir_decode/include/ir_decode.h
+++ b/arduino-example/src/ir_decode/include/ir_decode.h
@@ -276,11 +276,10 @@ extern INT8 ir_binary_open(const UINT8 category, const UINT8 sub_category, UINT8
* parameters: key_code (in) - the code of pressed key
* user_data (out) - output decoded data in INT16 array format
* ac_status(in) - pointer to AC status (optional)
- * change_wind_direction (in) - if control changes wind direction for AC (for AC only)
*
* returns: length of decoded data (0 indicates decode failure)
*/
-extern UINT16 ir_decode(UINT8 key_code, UINT16* user_data, t_remote_ac_status* ac_status, BOOL change_wind_direction);
+extern UINT16 ir_decode(UINT8 key_code, UINT16* user_data, t_remote_ac_status* ac_status);
/**
* function ir_close
@@ -362,7 +361,7 @@ extern void ir_lib_free_inner_buffer();
UINT16 ir_decode_combo(const UINT8 category, const UINT8 sub_category,
UINT8* binary, UINT16 bin_length,
UINT8 key_code, UINT16* user_data,
- t_remote_ac_status* ac_status, BOOL change_wind_direction);
+ t_remote_ac_status* ac_status);
#ifdef __cplusplus
}
diff --git a/arduino-example/src/ir_decode/include/ir_defs.h b/arduino-example/src/ir_decode/include/ir_defs.h
index dc471ec..dc98d95 100644
--- a/arduino-example/src/ir_decode/include/ir_defs.h
+++ b/arduino-example/src/ir_decode/include/ir_defs.h
@@ -12,7 +12,7 @@ Revision log:
#ifndef _IR_DEFS_H
#define _IR_DEFS_H
-#define IR_DECODE_LIB_VER "1.5.0"
+#define IR_DECODE_LIB_VER "1.5.2"
#if defined (BOARD_PC)
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
@@ -29,6 +29,10 @@ extern "C"
#define LOG_TAG "ir_decode"
#endif
+#if defined BOARD_ARDUINO
+#include "serial_log.h"
+#endif
+
#define TRUE 1
#define FALSE 0
@@ -59,10 +63,10 @@ void noprint(const char *fmt, ...);
#define ir_strlen(A) strlen(A)
#if ((defined BOARD_PC) || (defined BOARD_PC_JNI)) && (defined DEBUG)
#define ir_printf(...) do { printf(__VA_ARGS__); fflush(stdout); } while(0)
-#else
-#define ir_printf noprint
+#elif (defined BOARD_ARDUINO)
+#define ir_printf(...) do { serialPrint(LOG_DEBUG, __VA_ARGS__); } while(0)
#endif
-#define USER_DATA_SIZE 1636
+#define USER_DATA_SIZE 2048
// #define USER_DATA_SIZE 4096
#ifdef __cplusplus
diff --git a/arduino-example/src/ir_decode/ir_ac_apply.c b/arduino-example/src/ir_decode/ir_ac_apply.c
index 1dc8881..08c2e21 100644
--- a/arduino-example/src/ir_decode/ir_ac_apply.c
+++ b/arduino-example/src/ir_decode/ir_ac_apply.c
@@ -13,8 +13,8 @@ Revision log:
#pragma ide diagnostic ignored "hicpp-signed-bitwise"
#endif
-#include "include/ir_utils.h"
-#include "include/ir_ac_apply.h"
+#include "ir_utils.h"
+#include "ir_ac_apply.h"
static INT8 apply_ac_power(struct ac_protocol *protocol, UINT8 power_status);
@@ -616,17 +616,17 @@ INT8 apply_checksum(struct ac_protocol *protocol)
return IR_DECODE_SUCCEEDED;
}
-INT8 apply_power(t_remote_ac_status ac_status, UINT8 function_code)
+INT8 apply_power(t_remote_ac_status *ac_status, UINT8 function_code)
{
(void) function_code;
- apply_ac_power(context, ac_status.ac_power);
+ apply_ac_power(context, ac_status->ac_power);
return IR_DECODE_SUCCEEDED;
}
-INT8 apply_mode(t_remote_ac_status ac_status, UINT8 function_code)
+INT8 apply_mode(t_remote_ac_status *ac_status, UINT8 function_code)
{
(void) function_code;
- if (IR_DECODE_FAILED == apply_ac_mode(context, ac_status.ac_mode))
+ if (IR_DECODE_FAILED == apply_ac_mode(context, ac_status->ac_mode))
{
// do not implement this mechanism since mode, temperature, wind
// speed would have unspecified function
@@ -639,16 +639,16 @@ INT8 apply_mode(t_remote_ac_status ac_status, UINT8 function_code)
return IR_DECODE_SUCCEEDED;
}
-INT8 apply_wind_speed(t_remote_ac_status ac_status, UINT8 function_code)
+INT8 apply_wind_speed(t_remote_ac_status *ac_status, UINT8 function_code)
{
- if (FALSE == context->n_mode[ac_status.ac_mode].all_speed)
+ if (FALSE == context->n_mode[ac_status->ac_mode].all_speed)
{
// if this level is not in black list
- if (!is_in(context->n_mode[ac_status.ac_mode].speed,
- ac_status.ac_wind_speed,
- context->n_mode[ac_status.ac_mode].speed_cnt))
+ if (!is_in(context->n_mode[ac_status->ac_mode].speed,
+ ac_status->ac_wind_speed,
+ context->n_mode[ac_status->ac_mode].speed_cnt))
{
- if (IR_DECODE_FAILED == apply_ac_wind_speed(context, ac_status.ac_wind_speed) &&
+ if (IR_DECODE_FAILED == apply_ac_wind_speed(context, ac_status->ac_wind_speed) &&
function_code == AC_FUNCTION_WIND_SPEED)
{
// do not implement this mechanism since mode, temperature, wind
@@ -689,7 +689,7 @@ INT8 apply_wind_speed(t_remote_ac_status ac_status, UINT8 function_code)
return IR_DECODE_SUCCEEDED;
}
-INT8 apply_swing(t_remote_ac_status ac_status, UINT8 function_code)
+INT8 apply_swing(t_remote_ac_status *ac_status, UINT8 function_code)
{
(void) ac_status;
if (function_code == AC_FUNCTION_WIND_FIX)
@@ -697,7 +697,7 @@ INT8 apply_swing(t_remote_ac_status ac_status, UINT8 function_code)
// adjust fixed wind direction according to current status
if (context->si.type == SWING_TYPE_NORMAL && context->si.mode_count > 1)
{
- if (TRUE == context->change_wind_direction)
+ if (1 == context->change_wind_direction)
{
context->si.dir_index++;
}
@@ -735,15 +735,15 @@ INT8 apply_swing(t_remote_ac_status ac_status, UINT8 function_code)
return IR_DECODE_SUCCEEDED;
}
-INT8 apply_temperature(t_remote_ac_status ac_status, UINT8 function_code)
+INT8 apply_temperature(t_remote_ac_status *ac_status, UINT8 function_code)
{
- if (FALSE == context->n_mode[ac_status.ac_mode].all_temp)
+ if (FALSE == context->n_mode[ac_status->ac_mode].all_temp)
{
- if (!is_in(context->n_mode[ac_status.ac_mode].temp,
- ac_status.ac_temp,
- context->n_mode[ac_status.ac_mode].temp_cnt))
+ if (!is_in(context->n_mode[ac_status->ac_mode].temp,
+ ac_status->ac_temp,
+ context->n_mode[ac_status->ac_mode].temp_cnt))
{
- if (IR_DECODE_FAILED == apply_ac_temperature(context, ac_status.ac_temp))
+ if (IR_DECODE_FAILED == apply_ac_temperature(context, ac_status->ac_temp))
{
if (function_code == AC_FUNCTION_TEMPERATURE_UP
/*&& FALSE == has_function(context, AC_FUNCTION_TEMPERATURE_UP)*/)
diff --git a/arduino-example/src/ir_decode/ir_ac_binary_parse.c b/arduino-example/src/ir_decode/ir_ac_binary_parse.c
index de1f016..4b8ee1e 100644
--- a/arduino-example/src/ir_decode/ir_ac_binary_parse.c
+++ b/arduino-example/src/ir_decode/ir_ac_binary_parse.c
@@ -9,8 +9,8 @@ Revision log:
* 2017-01-03: created by strawmanbobi
**************************************************************************************/
-#include "include/ir_ac_binary_parse.h"
-#include "include/ir_decode.h"
+#include "ir_ac_binary_parse.h"
+#include "ir_decode.h"
UINT16 tag_head_offset = 0;
diff --git a/arduino-example/src/ir_decode/ir_ac_build_frame.c b/arduino-example/src/ir_decode/ir_ac_build_frame.c
index 366e08c..38c4d18 100644
--- a/arduino-example/src/ir_decode/ir_ac_build_frame.c
+++ b/arduino-example/src/ir_decode/ir_ac_build_frame.c
@@ -14,8 +14,8 @@ Revision log:
#pragma ide diagnostic ignored "readability-redundant-declaration"
#endif
-#include "include/ir_ac_build_frame.h"
-#include "include/ir_decode.h"
+#include "ir_ac_build_frame.h"
+#include "ir_decode.h"
extern t_ac_protocol* context;
diff --git a/arduino-example/src/ir_decode/ir_ac_control.c b/arduino-example/src/ir_decode/ir_ac_control.c
index e6ee7b7..b012968 100644
--- a/arduino-example/src/ir_decode/ir_ac_control.c
+++ b/arduino-example/src/ir_decode/ir_ac_control.c
@@ -13,13 +13,13 @@ Revision log:
#include
#include
-#include "include/ir_ac_control.h"
-#include "include/ir_ac_binary_parse.h"
-#include "include/ir_decode.h"
-#include "include/ir_ac_parse_parameter.h"
-#include "include/ir_ac_parse_forbidden_info.h"
-#include "include/ir_ac_parse_frame_info.h"
-#include "include/ir_utils.h"
+#include "ir_ac_control.h"
+#include "ir_ac_binary_parse.h"
+#include "ir_decode.h"
+#include "ir_ac_parse_parameter.h"
+#include "ir_ac_parse_forbidden_info.h"
+#include "ir_ac_parse_frame_info.h"
+#include "ir_utils.h"
#if defined USE_DYNAMIC_TAG
diff --git a/arduino-example/src/ir_decode/ir_ac_parse_forbidden_info.c b/arduino-example/src/ir_decode/ir_ac_parse_forbidden_info.c
index 5121932..64e5991 100644
--- a/arduino-example/src/ir_decode/ir_ac_parse_forbidden_info.c
+++ b/arduino-example/src/ir_decode/ir_ac_parse_forbidden_info.c
@@ -17,8 +17,8 @@ Revision log:
#include
#include
-#include "include/ir_decode.h"
-#include "include/ir_ac_parse_forbidden_info.h"
+#include "ir_decode.h"
+#include "ir_ac_parse_forbidden_info.h"
extern t_ac_protocol *context;
diff --git a/arduino-example/src/ir_decode/ir_ac_parse_frame_info.c b/arduino-example/src/ir_decode/ir_ac_parse_frame_info.c
index d103815..b416ce8 100644
--- a/arduino-example/src/ir_decode/ir_ac_parse_frame_info.c
+++ b/arduino-example/src/ir_decode/ir_ac_parse_frame_info.c
@@ -10,11 +10,10 @@ Revision log:
**************************************************************************************/
#include
-#include
#include
-#include "include/ir_utils.h"
-#include "include/ir_ac_parse_frame_info.h"
+#include "ir_utils.h"
+#include "ir_ac_parse_frame_info.h"
INT8 parse_boot_code(struct tag_head *tag)
@@ -341,5 +340,13 @@ INT8 parse_bit_num(struct tag_head *tag)
if (context->bit_num[i].pos == -1)
context->bit_num[i].pos = (UINT16) (context->default_code.len - 1); //convert -1 to last data pos
}
+
+ // Ensure bit_num_cnt does not exceed MAX_BITNUM to prevent buffer overflow
+ if (context->bit_num_cnt > MAX_BITNUM)
+ {
+ ir_printf("Warning: bit_num_cnt (%d) exceeds MAX_BITNUM (%d), limiting to MAX_BITNUM\n",
+ context->bit_num_cnt, MAX_BITNUM);
+ context->bit_num_cnt = MAX_BITNUM;
+ }
return IR_DECODE_SUCCEEDED;
}
diff --git a/arduino-example/src/ir_decode/ir_ac_parse_parameter.c b/arduino-example/src/ir_decode/ir_ac_parse_parameter.c
index d8d2a03..97aeba6 100644
--- a/arduino-example/src/ir_decode/ir_ac_parse_parameter.c
+++ b/arduino-example/src/ir_decode/ir_ac_parse_parameter.c
@@ -13,8 +13,8 @@ Revision log:
#include
#include
-#include "include/ir_utils.h"
-#include "include/ir_ac_parse_parameter.h"
+#include "ir_utils.h"
+#include "ir_ac_parse_parameter.h"
static INT8 parse_checksum_byte_typed(const UINT8 *csdata, t_tag_checksum_data *checksum, UINT16 len);
@@ -236,6 +236,13 @@ INT8 parse_temp_1(struct tag_head *tag, t_temp_1 *temp1)
temp1->len = (UINT8) hex_len;
UINT8 seg_len = hex_data[0];
+ // Initialize all segments to NULL to ensure proper cleanup in case of error
+ for (seg_index = AC_TEMP_16; seg_index < (UINT16) AC_TEMP_MAX; seg_index++)
+ {
+ temp1->comp_data[seg_index].seg_len = 0;
+ temp1->comp_data[seg_index].segment = NULL;
+ }
+
for (seg_index = AC_TEMP_16; seg_index < (UINT16) AC_TEMP_MAX; seg_index++)
{
// 020210 indicates set the 02nd byte to [default] +10, +11, +12, +...
@@ -243,6 +250,17 @@ INT8 parse_temp_1(struct tag_head *tag, t_temp_1 *temp1)
temp1->comp_data[seg_index].segment = (UINT8 *) ir_malloc(seg_len);
if (NULL == temp1->comp_data[seg_index].segment)
{
+ // Clean up previously allocated memory
+ UINT16 cleanup_idx;
+ for (cleanup_idx = AC_TEMP_16; cleanup_idx < seg_index; cleanup_idx++)
+ {
+ if (temp1->comp_data[cleanup_idx].segment != NULL)
+ {
+ ir_free(temp1->comp_data[cleanup_idx].segment);
+ temp1->comp_data[cleanup_idx].segment = NULL;
+ temp1->comp_data[cleanup_idx].seg_len = 0;
+ }
+ }
ir_free(hex_data);
return IR_DECODE_FAILED;
}
@@ -400,10 +418,30 @@ INT8 parse_swing_1(struct tag_head *tag, t_swing_1 *swing1, UINT16 swing_count)
return IR_DECODE_FAILED;
}
+ // Initialize the comp_data to ensure proper cleanup in case of error
+ for (seg_index = 0; seg_index < swing_count; seg_index++)
+ {
+ swing1->comp_data[seg_index].seg_len = 0;
+ swing1->comp_data[seg_index].segment = NULL;
+ }
+
for (seg_index = 0; seg_index < swing_count; seg_index++)
{
if (IR_DECODE_FAILED == parse_comp_data_type_1(hex_data, &trav_offset, &swing1->comp_data[seg_index]))
{
+ // Clean up any allocated memory in previous iterations
+ UINT16 i;
+ for (i = 0; i < seg_index; i++)
+ {
+ if (swing1->comp_data[i].segment != NULL)
+ {
+ ir_free(swing1->comp_data[i].segment);
+ swing1->comp_data[i].segment = NULL;
+ swing1->comp_data[i].seg_len = 0;
+ }
+ }
+ ir_free(swing1->comp_data);
+ swing1->comp_data = NULL;
ir_free(hex_data);
return IR_DECODE_FAILED;
}
@@ -518,6 +556,16 @@ INT8 parse_checksum(struct tag_head *tag, t_checksum *checksum)
checksum->checksum_data + num,
(UINT8) (i - preindex) >> (UINT8) 1))
{
+ // Clean up allocated memory on error
+ UINT16 j;
+ for (j = 0; j < num; j++) {
+ if (checksum->checksum_data[j].spec_pos != NULL) {
+ ir_free(checksum->checksum_data[j].spec_pos);
+ checksum->checksum_data[j].spec_pos = NULL;
+ }
+ }
+ ir_free(checksum->checksum_data);
+ checksum->checksum_data = NULL;
return IR_DECODE_FAILED;
}
preindex = (UINT16) (i + 1);
@@ -529,6 +577,16 @@ INT8 parse_checksum(struct tag_head *tag, t_checksum *checksum)
checksum->checksum_data + num,
(UINT8) (i - preindex) >> (UINT8) 1))
{
+ // Clean up allocated memory on error
+ UINT16 j;
+ for (j = 0; j <= num; j++) {
+ if (checksum->checksum_data[j].spec_pos != NULL) {
+ ir_free(checksum->checksum_data[j].spec_pos);
+ checksum->checksum_data[j].spec_pos = NULL;
+ }
+ }
+ ir_free(checksum->checksum_data);
+ checksum->checksum_data = NULL;
return IR_DECODE_FAILED;
}
@@ -635,18 +693,12 @@ INT8 parse_function_1_tag29(struct tag_head *tag, t_function_1 *function1)
// seg_index in TAG only refers to functional count
for (seg_index = AC_FUNCTION_POWER; seg_index < (UINT16) AC_FUNCTION_MAX; seg_index++)
{
- /** WARNING: for strict mode only **/
- /**
- INT8 fid = parse_function_1(hex_data, &trav_offset, &function1->comp_data[0]);
- if (fid > AC_FUNCTION_MAX - 1)
+ INT8 result = parse_function_1(hex_data, &trav_offset, &function1->comp_data[0]);
+ if (result == IR_DECODE_FAILED)
{
- irda_free(hex_data);
- hex_data = NULL;
+ ir_free(hex_data);
return IR_DECODE_FAILED;
}
- **/
-
- parse_function_1(hex_data, &trav_offset, &function1->comp_data[0]);
if (trav_offset >= hex_len)
{
break;
@@ -694,6 +746,13 @@ INT8 parse_temp_2(struct tag_head *tag, t_temp_2 *temp2)
temp2->len = (UINT8) hex_len;
UINT8 seg_len = hex_data[0];
+ // Initialize all segments to NULL to ensure proper cleanup in case of error
+ for (seg_index = AC_TEMP_16; seg_index < (UINT16) AC_TEMP_MAX; seg_index++)
+ {
+ temp2->comp_data[seg_index].seg_len = 0;
+ temp2->comp_data[seg_index].segment = NULL;
+ }
+
for (seg_index = AC_TEMP_16; seg_index < (UINT16) AC_TEMP_MAX; seg_index++)
{
// 020210 indicates set the 02nd byte to [default] +10, +11, +12, +...
@@ -701,6 +760,17 @@ INT8 parse_temp_2(struct tag_head *tag, t_temp_2 *temp2)
temp2->comp_data[seg_index].segment = (UINT8 *) ir_malloc(seg_len);
if (NULL == temp2->comp_data[seg_index].segment)
{
+ // Clean up previously allocated memory
+ UINT16 cleanup_idx;
+ for (cleanup_idx = AC_TEMP_16; cleanup_idx < seg_index; cleanup_idx++)
+ {
+ if (temp2->comp_data[cleanup_idx].segment != NULL)
+ {
+ ir_free(temp2->comp_data[cleanup_idx].segment);
+ temp2->comp_data[cleanup_idx].segment = NULL;
+ temp2->comp_data[cleanup_idx].seg_len = 0;
+ }
+ }
ir_free(hex_data);
return IR_DECODE_FAILED;
}
@@ -873,10 +943,30 @@ INT8 parse_swing_2(struct tag_head *tag, t_swing_2 *swing2, UINT16 swing_count)
return IR_DECODE_FAILED;
}
+ // Initialize the comp_data to ensure proper cleanup in case of error
+ for (seg_index = 0; seg_index < swing_count; seg_index++)
+ {
+ swing2->comp_data[seg_index].seg_len = 0;
+ swing2->comp_data[seg_index].segment = NULL;
+ }
+
for (seg_index = 0; seg_index < swing_count; seg_index++)
{
if (IR_DECODE_FAILED == parse_comp_data_type_2(hex_data, &trav_offset, &swing2->comp_data[seg_index]))
{
+ // Clean up any allocated memory in previous iterations
+ UINT16 i;
+ for (i = 0; i < seg_index; i++)
+ {
+ if (swing2->comp_data[i].segment != NULL)
+ {
+ ir_free(swing2->comp_data[i].segment);
+ swing2->comp_data[i].segment = NULL;
+ swing2->comp_data[i].seg_len = 0;
+ }
+ }
+ ir_free(swing2->comp_data);
+ swing2->comp_data = NULL;
ir_free(hex_data);
return IR_DECODE_FAILED;
}
@@ -993,18 +1083,12 @@ INT8 parse_function_2_tag34(struct tag_head *tag, t_function_2 *function2)
// seg_index in TAG only refers to functional count
for (seg_index = AC_FUNCTION_POWER; seg_index < (UINT16) AC_FUNCTION_MAX; seg_index++)
{
- /** WARNING: for strict mode only **/
- /**
- INT8 fid = parse_function_2(hex_data, &trav_offset, &function2->comp_data[0]);
- if (fid > AC_FUNCTION_MAX - 1)
+ INT8 result = parse_function_2(hex_data, &trav_offset, &function2->comp_data[0]);
+ if (result == IR_DECODE_FAILED)
{
- irda_free(hex_data);
- hex_data = NULL;
+ ir_free(hex_data);
return IR_DECODE_FAILED;
}
- **/
-
- parse_function_2(hex_data, &trav_offset, &function2->comp_data[0]);
if (trav_offset >= hex_len)
{
break;
diff --git a/arduino-example/src/ir_decode/ir_decode.c b/arduino-example/src/ir_decode/ir_decode.c
index 0865f42..eb314fb 100644
--- a/arduino-example/src/ir_decode/ir_decode.c
+++ b/arduino-example/src/ir_decode/ir_decode.c
@@ -14,10 +14,10 @@ Revision log:
#include
-#include "include/ir_decode.h"
-#include "include/ir_utils.h"
-#include "include/ir_ac_build_frame.h"
-#include "include/ir_ac_apply.h"
+#include "ir_decode.h"
+#include "ir_utils.h"
+#include "ir_ac_build_frame.h"
+#include "ir_ac_apply.h"
struct ir_bin_buffer binary_file;
struct ir_bin_buffer *p_ir_buffer = &binary_file;
@@ -79,18 +79,23 @@ static INT8 ir_ac_file_open(const char *file_name);
#endif
static INT8 ir_ac_binary_open(UINT8 *binary, UINT16 bin_length);
-static UINT16 ir_ac_control(t_remote_ac_status ac_status, UINT16* user_data, UINT8 key_code,
- BOOL change_wind_direction);
+
+static UINT16 ir_ac_control(t_remote_ac_status *ac_status, UINT16* user_data, UINT8 key_code);
+
static INT8 ir_ac_binary_close();
-static BOOL validate_ac_status(t_remote_ac_status* ac_status, BOOL change_wind_dir);
+
+static BOOL validate_ac_status(t_remote_ac_status* ac_status);
#if !defined NO_FS
static INT8 ir_tv_file_open(const char *file_name);
#endif
static INT8 ir_tv_binary_open(UINT8 *binary, UINT16 bin_length);
+
static INT8 ir_tv_binary_parse(UINT8 ir_hex_encode);
+
static UINT16 ir_tv_control(UINT8 key, UINT16 *l_user_data);
+
static INT8 ir_tv_binary_close();
@@ -244,8 +249,7 @@ INT8 ir_binary_open(const UINT8 category, const UINT8 sub_category, UINT8* binar
}
/** the main entry of decode algorithm **/
-UINT16 ir_decode(UINT8 key_code, UINT16* user_data,
- t_remote_ac_status* ac_status, BOOL change_wind_direction)
+UINT16 ir_decode(UINT8 key_code, UINT16* user_data, t_remote_ac_status* ac_status)
{
ir_printf("remote_category = %d, KEY_CODE_MAX = %d\n", remote_category, KEY_CODE_MAX[remote_category]);
@@ -266,21 +270,21 @@ UINT16 ir_decode(UINT8 key_code, UINT16* user_data,
return 0;
}
ir_printf("ac status is not null in decode core : power = %d, mode = %d, "
- "temp = %d, wind_dir = %d, wind_speed = %d, "
- "key_code = %d, change_wind_direction = %d\n",
+ "temp = %d, wind_dir = %d, wind_speed = %d, change_wind_direction = %d, "
+ "key_code = %d\n",
ac_status->ac_power, ac_status->ac_mode,
ac_status->ac_temp, ac_status->ac_wind_dir,
ac_status->ac_wind_speed,
- key_code, change_wind_direction);
+ ac_status->change_wind_direction,
+ key_code);
// ac status validation
- if (FALSE == validate_ac_status(ac_status, change_wind_direction)) {
+ if (FALSE == validate_ac_status(ac_status)) {
return 0;
}
- return ir_ac_control(*ac_status, user_data, key_code, change_wind_direction);
+ return ir_ac_control(ac_status, user_data, key_code);
}
}
-
INT8 ir_close()
{
if (IR_TYPE_COMMANDS == ir_binary_type)
@@ -359,8 +363,7 @@ static INT8 ir_ac_binary_open(UINT8 *binary, UINT16 bin_length)
return IR_DECODE_SUCCEEDED;
}
-static UINT16 ir_ac_control(t_remote_ac_status ac_status, UINT16* user_data, UINT8 key_code,
- BOOL change_wind_direction)
+static UINT16 ir_ac_control(t_remote_ac_status *ac_status, UINT16* user_data, UINT8 key_code)
{
UINT16 time_length = 0;
UINT8 function_code = 0;
@@ -402,7 +405,7 @@ static UINT16 ir_ac_control(t_remote_ac_status ac_status, UINT16* user_data, UIN
}
// pre-set change wind direction flag here
- context->change_wind_direction = change_wind_direction;
+ context->change_wind_direction = ac_status->change_wind_direction;
context->time = user_data;
@@ -410,15 +413,16 @@ static UINT16 ir_ac_control(t_remote_ac_status ac_status, UINT16* user_data, UIN
ir_memcpy(ir_hex_code, context->default_code.data, context->default_code.len);
#if defined USE_APPLY_TABLE
- if(ac_status.ac_power != AC_POWER_OFF)
+ if(ac_status->ac_power != AC_POWER_OFF)
{
+ UINT8 i;
for (i = AC_APPLY_POWER; i < AC_APPLY_MAX; i++)
{
- apply_table[i](context, parameter_array[i]);
+ apply_table[i](ac_status, function_code);
}
}
#else
- if (ac_status.ac_power == AC_POWER_OFF)
+ if (ac_status->ac_power == AC_POWER_OFF)
{
// otherwise, power should always be applied
apply_power(ac_status, function_code);
@@ -426,7 +430,7 @@ static UINT16 ir_ac_control(t_remote_ac_status ac_status, UINT16* user_data, UIN
else
{
// check the mode as the first priority, despite any other status
- if (TRUE == context->n_mode[ac_status.ac_mode].enable)
+ if (TRUE == context->n_mode[ac_status->ac_mode].enable)
{
if (is_solo_function(function_code))
{
@@ -506,7 +510,7 @@ static INT8 ir_ac_binary_close()
return IR_DECODE_SUCCEEDED;
}
-static BOOL validate_ac_status(t_remote_ac_status* ac_status, BOOL change_wind_dir)
+static BOOL validate_ac_status(t_remote_ac_status* ac_status)
{
if (AC_POWER_OFF != ac_status->ac_power && AC_POWER_ON != ac_status->ac_power)
{
@@ -528,7 +532,7 @@ static BOOL validate_ac_status(t_remote_ac_status* ac_status, BOOL change_wind_d
{
return FALSE;
}
- if (0 != change_wind_dir && 1 != change_wind_dir)
+ if (0 != ac_status->change_wind_direction && 1 != ac_status->change_wind_direction)
{
return FALSE;
}
@@ -776,7 +780,7 @@ static INT8 ir_tv_binary_close()
UINT16 ir_decode_combo(const UINT8 category, const UINT8 sub_category,
UINT8* binary, UINT16 bin_length,
UINT8 key_code, UINT16* user_data,
- t_remote_ac_status* ac_status, BOOL change_wind_direction)
+ t_remote_ac_status* ac_status)
{
UINT16 decoded_length = 0;
@@ -787,6 +791,13 @@ UINT16 ir_decode_combo(const UINT8 category, const UINT8 sub_category,
return IR_DECODE_FAILED;
}
+ if (sub_category < SUB_CATEGORY_QUATERNARY ||
+ sub_category >= SUB_CATEGORY_NEXT)
+ {
+ ir_printf("wrong remote sub category : %d\n", sub_category);
+ return IR_DECODE_FAILED;
+ }
+
remote_category = (t_remote_category) category;
if (key_code < 0 || key_code >= KEY_CODE_MAX[remote_category])
@@ -798,7 +809,7 @@ UINT16 ir_decode_combo(const UINT8 category, const UINT8 sub_category,
if (IR_DECODE_SUCCEEDED ==
ir_binary_open(category, sub_category, binary, bin_length))
{
- decoded_length = ir_decode(key_code, user_data, ac_status, change_wind_direction);
+ decoded_length = ir_decode(key_code, user_data, ac_status);
ir_close();
return decoded_length;
}
diff --git a/arduino-example/src/ir_decode/ir_tv_control.c b/arduino-example/src/ir_decode/ir_tv_control.c
index 53a3e80..e922dc3 100644
--- a/arduino-example/src/ir_decode/ir_tv_control.c
+++ b/arduino-example/src/ir_decode/ir_tv_control.c
@@ -15,9 +15,9 @@ Revision log:
#include
-#include "include/ir_defs.h"
-#include "include/ir_decode.h"
-#include "include/ir_tv_control.h"
+#include "ir_defs.h"
+#include "ir_decode.h"
+#include "ir_tv_control.h"
struct buffer
@@ -249,8 +249,16 @@ static void print_ir_time(t_ir_data *data, UINT8 key_index, UINT16 *ir_time)
}
else if (ir_level == IRDA_LEVEL_LOW)
{
+ if (time_index + 1 > USER_DATA_SIZE) {
+ ir_printf("time index exceeded\n");
+ return;
+ }
ir_time[time_index++] = pcycles->mask;
}
+ if (time_index + 1 > USER_DATA_SIZE) {
+ ir_printf("time index exceeded\n");
+ return;
+ }
ir_time[time_index++] = pcycles->space;
ir_level = IRDA_LEVEL_LOW;
}
@@ -263,8 +271,16 @@ static void print_ir_time(t_ir_data *data, UINT8 key_index, UINT16 *ir_time)
}
else if (ir_level == IRDA_LEVEL_HIGH)
{
+ if (time_index + 1 > USER_DATA_SIZE) {
+ ir_printf("time index exceeded\n");
+ return;
+ }
ir_time[time_index++] = pcycles->space;
}
+ if (time_index + 1 > USER_DATA_SIZE) {
+ ir_printf("time index exceeded\n");
+ return;
+ }
ir_time[time_index++] = pcycles->mask;
ir_level = IRDA_LEVEL_HIGH;
}
@@ -278,6 +294,10 @@ static void print_ir_time(t_ir_data *data, UINT8 key_index, UINT16 *ir_time)
}
else if (ir_level == IRDA_LEVEL_HIGH)
{
+ if (time_index + 1 > USER_DATA_SIZE) {
+ ir_printf("time index exceeded\n");
+ return;
+ }
ir_time[time_index++] = pcycles->space;
}
ir_level = IRDA_LEVEL_LOW;
@@ -291,6 +311,10 @@ static void print_ir_time(t_ir_data *data, UINT8 key_index, UINT16 *ir_time)
}
else if (ir_level == IRDA_LEVEL_LOW)
{
+ if (time_index + 1 > USER_DATA_SIZE) {
+ ir_printf("time index exceeded\n");
+ return;
+ }
ir_time[time_index++] = pcycles->mask;
}
ir_level = IRDA_LEVEL_HIGH;
diff --git a/arduino-example/src/ir_decode/ir_utils.c b/arduino-example/src/ir_decode/ir_utils.c
index 9045a52..7d90ea5 100644
--- a/arduino-example/src/ir_decode/ir_utils.c
+++ b/arduino-example/src/ir_decode/ir_utils.c
@@ -9,7 +9,7 @@ Revision log:
* 2016-10-01: created by strawmanbobi
**************************************************************************************/
-#include "include/ir_utils.h"
+#include "ir_utils.h"
UINT8 char_to_hex(char chr)
{
diff --git a/arduino-example/src/main.cpp b/arduino-example/src/main.cpp
index 4522214..b9cd17e 100644
--- a/arduino-example/src/main.cpp
+++ b/arduino-example/src/main.cpp
@@ -28,6 +28,7 @@
#include "configure.h"
#include "remote.h"
+#include "serial_log.h"
#define WIFI_SERVER_PORT (8000)
@@ -74,21 +75,18 @@ void printWiFiStatus() {
unsigned long currentMillis = millis();
if (currentMillis - lastStatusCheck >= ALIVE_DEBUG_INTERVAL) {
- IPAddress ip = WiFi.localIP();
+ const IPAddress ip = WiFi.localIP();
if (0 == strcmp(ip.toString().c_str(), "0.0.0.0")) {
lastStatusCheck = currentMillis;
return;
}
- Serial.print("SSID: ");
- Serial.println(WiFi.SSID());
+ serialPrint(LOG_INFO, "Wi-Fi SSID: %s", WiFi.SSID());
- Serial.print("IP address: ");
- Serial.println(ip);
+ serialPrint(LOG_INFO, "Wi-Fi IP address: %s", ip.toString().c_str());
const long rssi = WiFi.RSSI();
- Serial.print("Signal strength (RSSI): ");
- Serial.print(rssi);
- Serial.println(" dBm");
+ serialPrint(LOG_INFO, "Wi-Fi signal strength (RSSI): %ld dBm", rssi);
+
lastStatusCheck = currentMillis;
if (0 == wifiStatusPrinted) {
@@ -98,12 +96,20 @@ void printWiFiStatus() {
}
}
+static void sendToClient(WiFiClient *client, const char* content) {
+ client->println(content);
+ client->flush();
+}
+
void setup() {
Serial.begin(115200);
+
while (!Serial) {
delay(100);
}
+ remoteInit();
+
matrix.begin();
matrix.beginDraw();
@@ -117,33 +123,31 @@ void setup() {
matrix.endText(SCROLL_LEFT);
matrix.endDraw();
- Serial.println("IRext Arduino example started in station mode");
- Serial.print("Attempting to connect to SSID: ");
- Serial.println(ssid);
+ serialPrint(LOG_INFO, "IRext Arduino example started in station mode");
+ serialPrint(LOG_INFO, "Attempting to connect to SSID: %s", ssid);
status = WiFi.begin(ssid, pass);
if (status == WL_CONNECTED) {
- Serial.println("\nConnected to Wi-Fi");
+ serialPrint(LOG_INFO, "Connected to Wi-Fi");
server.begin();
}
else {
- Serial.print("\nFailed to connect Wi-Fi, status: ");
- Serial.println(status);
+ serialPrint(LOG_ERROR, "Failed to connect Wi-Fi, status: %d", status);
}
}
void onConnected(WiFiClient *client) {
client->flush();
- Serial.println("Client connected");
- client->println(eHello);
+ serialPrint(LOG_DEBUG, "Client connected");
+ sendToClient(client, eHello);
}
void onDisconnected(WiFiClient *client) {
remoteClose();
client->flush();
client->stop();
- Serial.println("Client disconnected");
+ serialPrint(LOG_DEBUG, "Client disconnected");
}
void onError(WiFiClient *client) {
@@ -151,54 +155,61 @@ void onError(WiFiClient *client) {
client->stop();
}
-void onCommand(const String *command, WiFiClient *client) {
+void onCommand(WiFiClient *client, const String *command) {
if (command->startsWith(aHello)) {
- Serial.println("Received hello command");
- client->println(eBin);
- client->flush();
+ serialPrint(LOG_DEBUG, "Received hello command");
+ sendToClient(client, eBin);
} else if (command->startsWith(aBin)) {
- Serial.println("Received bin command");
+ serialPrint(LOG_DEBUG, "Received bin command");
+#if !defined TEST_BIN_RECEIVE
if (remoteOpen(command->c_str()) > 0) {
- client->println(eControl);
+ sendToClient(client, eControl);
} else {
- Serial.println("Failed to parse bin command");
- client->println(eError);
+ serialPrint(LOG_ERROR, "Failed to parse bin command");
+ sendToClient(client, eError);
}
+#else
+ sendToClient(client, eControl);
+#endif
} else if (command->startsWith(aControl)) {
- Serial.println("Received control command");
+ serialPrint(LOG_DEBUG, "Received control command");
remoteControl(command->c_str());
} else if (command->startsWith(aError)) {
- Serial.println("Received error command");
+ serialPrint(LOG_DEBUG, "Received error command");
onError(client);
}
}
void loop() {
if (WiFi.status() != WL_CONNECTED) {
- Serial.print("Connection lost. Reconnecting...");
+ serialPrint(LOG_INFO, "Connection lost, reconnecting");
status = WiFi.begin(ssid, pass);
if (status == WL_CONNECTED) {
- Serial.println("Reconnected!");
+ serialPrint(LOG_INFO, "Reconnected");
}
} else {
printWiFiStatus();
- client = server.available();
- if (client.connected()) {
- if (false == clientConnected) {
+ if (!client || !client.connected()) {
+ client = server.available();
+ if (client) {
+ clientConnected = true;
onConnected(&client);
}
- clientConnected = true;
+ }
+ if (client && client.connected()) {
if (client.available()) {
- const String received = client.readStringUntil('\n');
- Serial.println(received);
- onCommand(&received, &client);
- }
- } else {
- if (clientConnected) {
- onDisconnected(&client);
+ String received = client.readStringUntil('\n');
+ received.trim();
+
+ if (received.length() > 0) {
+ serialPrint(LOG_VERBOSE, "Data received: %d", received.length());
+ onCommand(&client, &received);
+ }
}
+ } else if (clientConnected) {
+ onDisconnected(&client);
clientConnected = false;
+ client.stop();
}
}
- delay(10);
}
diff --git a/arduino-example/src/remote.cpp b/arduino-example/src/remote.cpp
index fcf1fac..81bb63f 100644
--- a/arduino-example/src/remote.cpp
+++ b/arduino-example/src/remote.cpp
@@ -23,89 +23,229 @@
#include
#include
+#include
+#include "control_command.h"
#include "utils.h"
+#include "serial_log.h"
#include "ir_decode.h"
+#include "remote.h"
-#define REMOTE_BIN_MAX (1024)
+#define REMOTE_BIN_MAX (1024)
-#define ABIN_COMMAND_SEG (5)
-#define SEG_ABIN_HEADER (0)
-#define SEG_ABIN_CATE (1)
-#define SEG_ABIN_SUBCATE (2)
-#define SEG_ABIN_LENGTH (3)
-#define SEG_ABIN_BIN (4)
+#define ABIN_COMMAND_SEG (5)
+#define ACTRL_COMMAND_SEG (3)
-// global variable definitions
-unsigned char *remoteBin = nullptr;
-int remoteBinLen = 0;
+#define SEG_ABIN_HEADER (0)
+#define SEG_ABIN_CATE (1)
+#define SEG_ABIN_SUBCATE (2)
+#define SEG_ABIN_LENGTH (3)
+#define SEG_ABIN_BIN (4)
+#define SEG_ACTRL_HEADER (0)
+#define SEG_ACTRL_LENGTH (1)
+#define SEG_ACTRL_COMMAND (2)
+
+#define IR_SEND_PIN 3
+
+
+// external variable declarations
+extern char *eError;
+
+
+// private variable definitions
+static uint8_t categoryId = -1;
+static uint8_t subCategoryId = -1;
+static unsigned char *remoteBin = nullptr;
+static int remoteBinLen = 0;
+static uint16_t remoteUserData[USER_DATA_SIZE] = { 0 };
+static uint16_t userDataLen = 0;
// public function definitions
+void remoteInit() {
+ IrSender.begin(IR_SEND_PIN);
+}
+
int remoteOpen(const char *binStr) {
char *aBinCommand[ABIN_COMMAND_SEG];
char *remoteBinStr = nullptr;
- int categoryId = 0;
- int subCateId = 0;
int aBinCommandSeg = 0;
int remoteBinBase64Len = 0;
+ int retVal = 0;
aBinCommandSeg = splitString(binStr, aBinCommand, ABIN_COMMAND_SEG, ",");
if (ABIN_COMMAND_SEG != aBinCommandSeg) {
- Serial.print("Invalid aBin command: ");
- Serial.println(binStr);
- return -1;
+ serialPrint(LOG_ERROR, "Invalid aBin command: %s", binStr);
+ retVal = -1;
+ goto _exit;
}
categoryId = strtol(aBinCommand[SEG_ABIN_CATE], nullptr, 10);
- subCateId = strtol(aBinCommand[SEG_ABIN_SUBCATE], nullptr, 10);
+ subCategoryId = strtol(aBinCommand[SEG_ABIN_SUBCATE], nullptr, 10);
remoteBinBase64Len = strtol(aBinCommand[SEG_ABIN_LENGTH], nullptr, 10);
remoteBinStr = aBinCommand[SEG_ABIN_BIN];
if (remoteBinBase64Len != strlen(remoteBinStr)) {
- Serial.println("Remote bin length not correct");
- return -1;
+ serialPrint(LOG_ERROR, "Remote bin length not correct, expected : %d, decoded : %d",
+ remoteBinBase64Len, remoteBinLen);
+ retVal = -1;
+ goto _exit;
}
remoteBinLen = base64_dec_len(remoteBinStr, remoteBinBase64Len);
+
+ // free the previously used buffer
+ if (nullptr != remoteBin) {
+ free(remoteBin);
+ remoteBin = nullptr;
+ }
remoteBin = static_cast(malloc(remoteBinLen));
- char debugStr[129];
if (nullptr == remoteBin) {
- Serial.println("Not enough memory for remote bin");
- return -1;
+ serialPrint(LOG_ERROR, "Not enough memory for remote bin");
+ retVal = -1;
+ goto _exit;
}
memset(remoteBin, 0, remoteBinLen);
if (remoteBinLen != base64_decode(reinterpret_cast(remoteBin), remoteBinStr, remoteBinBase64Len)) {
- Serial.println("Failed to decode remote bin");
- return -1;
+ serialPrint(LOG_ERROR, "Failed to decode remote bin");
+ retVal = -1;
+ goto _exit;
}
-#if defined REMOTE_BIN_DEBUG
- Serial.print("Remote bin length = ");
- Serial.println(remoteBinLen);
- snprintf(debugStr, 128, "%02x %02x %02x %02x %02x %02x %02x %02x",
- remoteBin[0], remoteBin[1], remoteBin[2], remoteBin[3],
- remoteBin[4], remoteBin[5], remoteBin[6], remoteBin[7]);
- Serial.println(debugStr);
- snprintf(debugStr, 128, "%02x %02x %02x %02x %02x %02x %02x %02x",
- remoteBin[remoteBinLen - 8], remoteBin[remoteBinLen - 7], remoteBin[remoteBinLen - 6], remoteBin[remoteBinLen - 5],
- remoteBin[remoteBinLen - 4], remoteBin[remoteBinLen - 3], remoteBin[remoteBinLen - 2], remoteBin[remoteBinLen - 1]);
- Serial.println(debugStr);
-#endif
-
- if (IR_DECODE_FAILED == ir_binary_open(categoryId, subCateId, remoteBin, remoteBinLen)) {
- Serial.println("Failed to load remote bin");
- return -1;
+ if (getLogLevel() == LOG_VERBOSE) {
+ char debugStr[129] = { 0 };
+ serialPrint(LOG_VERBOSE, "Remote bin(%d): ", remoteBinLen);
+ snprintf(debugStr, 128, "%02x %02x %02x %02x %02x %02x %02x %02x",
+ remoteBin[0], remoteBin[1], remoteBin[2], remoteBin[3],
+ remoteBin[4], remoteBin[5], remoteBin[6], remoteBin[7]);
+ serialPrint(LOG_VERBOSE, debugStr);
+ snprintf(debugStr, 128, "%02x %02x %02x %02x %02x %02x %02x %02x",
+ remoteBin[remoteBinLen - 8], remoteBin[remoteBinLen - 7], remoteBin[remoteBinLen - 6], remoteBin[remoteBinLen - 5],
+ remoteBin[remoteBinLen - 4], remoteBin[remoteBinLen - 3], remoteBin[remoteBinLen - 2], remoteBin[remoteBinLen - 1]);
+ serialPrint(LOG_VERBOSE, debugStr);
}
- Serial.println("Remote bin loaded successfully");
- return remoteBinLen;
+ if (IR_DECODE_FAILED == ir_binary_open(categoryId, subCategoryId, remoteBin, remoteBinLen)) {
+ serialPrint(LOG_ERROR, "Failed to load remote bin");
+ retVal = -1;
+ goto _exit;
+ }
+
+ retVal = remoteBinLen;
+ serialPrint(LOG_INFO, "Remote bin loaded successfully");
+
+_exit:
+ return retVal;
}
int remoteControl(const char *controlStr) {
- return 0;
+ char *aCtrlCommand[ACTRL_COMMAND_SEG];
+ char *commandStrBase64 = nullptr;
+ char *commandStr = nullptr;
+ int aCtrlCommandSeg = 0;
+ int commandBase64Len = 0;
+ int commandLen = 0;
+
+ t_remote_ac_status acStatus;
+ int keyCode = 0;
+
+ int retVal = 0;
+
+ aCtrlCommandSeg = splitString(controlStr, aCtrlCommand, ACTRL_COMMAND_SEG, ",");
+ if (ACTRL_COMMAND_SEG != aCtrlCommandSeg) {
+ serialPrint(LOG_ERROR, "Invalid aCtrl command: ");
+ retVal = -1;
+ goto _exit;
+ }
+ commandBase64Len = strtol(aCtrlCommand[SEG_ACTRL_LENGTH], nullptr, 10);
+ commandStrBase64 = aCtrlCommand[SEG_ACTRL_COMMAND];
+ if (commandBase64Len != strlen(commandStrBase64)) {
+ serialPrint(LOG_ERROR, "Remote command length not correct, expected : %d, decoded : %d",
+ commandBase64Len, commandStrBase64);
+ retVal = -1;
+ goto _exit;
+ }
+
+ commandLen = base64_dec_len(commandStrBase64, commandBase64Len);
+ commandStr = static_cast(malloc(commandLen));
+ if (nullptr == commandStr) {
+ serialPrint(LOG_ERROR, "Not enough memory for remote command");
+ retVal = -1;
+ goto _exit;
+ }
+ memset(commandStr, 0, commandLen);
+
+ if (commandLen != base64_decode(commandStr, commandStrBase64, commandBase64Len)) {
+ serialPrint(LOG_ERROR, "Failed to decode remote command");
+ retVal = -1;
+ goto _exit;
+ }
+
+ serialPrint(LOG_DEBUG, "Received remote command: %s", commandStr);
+
+ if (-1 != categoryId) {
+ if (0 != parseControlCommand(categoryId, commandStr, &acStatus, &keyCode)) {
+ serialPrint(LOG_ERROR, "Failed to parse command JSON");
+ retVal = -1;
+ goto _exit;
+ }
+ } else {
+ serialPrint(LOG_ERROR, "No remote bin loaded");
+ retVal = - 1;
+ goto _exit;
+ }
+
+ userDataLen = ir_decode(keyCode, remoteUserData, &acStatus);
+ if (userDataLen > 0) {
+ serialPrint(LOG_INFO, "IR decoded successfully: %d", userDataLen);
+ }
+ if (getLogLevel() == LOG_VERBOSE) {
+ remoteDebug(remoteUserData, userDataLen);
+ }
+
+ IrSender.sendRaw(remoteUserData, userDataLen, 38);
+ serialPrint(LOG_INFO, "IR sent successfully");
+
+ retVal = 0;
+_exit:
+
+ if (nullptr != commandStr) {
+ free(commandStr);
+ }
+
+ return retVal;
}
void remoteClose() {
+ serialPrint(LOG_INFO, "Closing remote");
ir_close();
+}
+
+
+// private function definitions
+void remoteDebug(const uint16_t* userData, const uint16_t userDataLen) {
+ if (userData == nullptr || userDataLen == 0) {
+ serialPrint(LOG_VERBOSE, "userData is empty or null");
+ return;
+ }
+
+ char debugStr[256] = { 0 };
+ int offset = 0;
+
+ for (uint16_t i = 0; i < userDataLen; i++) {
+ if (i % 16 == 0) {
+ offset = snprintf(debugStr, sizeof(debugStr), "userData[%d-%d]: ",
+ i, (i + 15 < userDataLen) ? i + 15 : userDataLen - 1);
+ }
+ offset += snprintf(debugStr + offset, sizeof(debugStr) - offset, "%d ", userData[i]);
+
+ if ((i + 1) % 16 == 0 || i == userDataLen - 1) {
+ serialPrint(LOG_VERBOSE, "%s", debugStr);
+ offset = 0;
+ }
+ }
+}
+
+int irControlSend() {
+
}
\ No newline at end of file
diff --git a/arduino-example/src/remote.h b/arduino-example/src/remote.h
index 29ed1c5..e863f3b 100644
--- a/arduino-example/src/remote.h
+++ b/arduino-example/src/remote.h
@@ -24,7 +24,11 @@
#ifndef ARDUINO_EXAMPLE_REMOTE_H
#define ARDUINO_EXAMPLE_REMOTE_H
-#define REMOTE_BIN_DEBUG (1)
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void remoteInit();
int remoteOpen(const char *binStr);
@@ -32,4 +36,9 @@ int remoteControl(const char *controlStr);
void remoteClose();
-#endif //ARDUINO_EXAMPLE_REMOTE_H
\ No newline at end of file
+void remoteDebug(const uint16_t* userData, uint16_t userDataLen);
+
+#ifdef __cplusplus
+}
+#endif
+#endif // ARDUINO_EXAMPLE_REMOTE_H
\ No newline at end of file
diff --git a/arduino-example/src/serial_log.cpp b/arduino-example/src/serial_log.cpp
new file mode 100644
index 0000000..a4b9e44
--- /dev/null
+++ b/arduino-example/src/serial_log.cpp
@@ -0,0 +1,59 @@
+/**
+*
+ * Copyright (c) 2020-2025 IRext Opensource Organization
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include
+#include
+#include
+#include
+
+#include "serial_log.h"
+
+#define LOG_BUF_SIZE (128)
+
+// public variable definitions
+int logLevel = LOG_VERBOSE;
+char logBuf[LOG_BUF_SIZE] = { 0 };
+
+
+// public function definitions
+void serialPrint(const int logType, const char* fmt, ...) {
+ if (logType < logLevel) {
+ return;
+ }
+ memset(logBuf, 0, LOG_BUF_SIZE);
+
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(logBuf, LOG_BUF_SIZE, fmt, ap);
+ va_end(ap);
+
+ Serial.println(logBuf);
+}
+
+void setLogLevel(const int level) {
+ logLevel = level;
+}
+
+int getLogLevel() {
+ return logLevel;
+}
\ No newline at end of file
diff --git a/arduino-example/src/serial_log.h b/arduino-example/src/serial_log.h
new file mode 100644
index 0000000..1fbeb57
--- /dev/null
+++ b/arduino-example/src/serial_log.h
@@ -0,0 +1,45 @@
+/**
+*
+ * Copyright (c) 2020-2025 IRext Opensource Organization
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef ARDUINO_EXAMPLE_SERIAL_LOG_H
+#define ARDUINO_EXAMPLE_SERIAL_LOG_H
+
+#define LOG_VERBOSE (0)
+#define LOG_DEBUG (1)
+#define LOG_INFO (2)
+#define LOG_ERROR (3)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void serialPrint(int logType, const char* fmt, ...);
+
+void setLogLevel(int level);
+
+int getLogLevel();
+
+#ifdef __cplusplus
+}
+#endif
+#endif // ARDUINO_EXAMPLE_SERIAL_LOG_H
\ No newline at end of file
diff --git a/arduino-example/src/utils.cpp b/arduino-example/src/utils.cpp
index e7f72e8..d436da2 100644
--- a/arduino-example/src/utils.cpp
+++ b/arduino-example/src/utils.cpp
@@ -22,9 +22,9 @@
*/
#include
-
#include
+#include "utils.h"
// public function definitions
int splitString(const char *str, char *parts[],
diff --git a/arduino-example/src/utils.h b/arduino-example/src/utils.h
index 3a4b885..cb3856f 100644
--- a/arduino-example/src/utils.h
+++ b/arduino-example/src/utils.h
@@ -24,7 +24,15 @@
#ifndef ARDUINO_EXAMPLE_UTILS_H
#define ARDUINO_EXAMPLE_UTILS_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
int splitString(const char *str, char *parts[],
int parts_max, const char *delimiter);
+#ifdef __cplusplus
+}
+#endif
+
#endif //ARDUINO_EXAMPLE_UTILS_H
\ No newline at end of file