Kaynağa Gözat

A133分机增加NFC刷卡进入医护功能,NFC模块接入串口7,测试模式中增加串口数据显示

weizhengliang 2 hafta önce
ebeveyn
işleme
40a796ee9d
22 değiştirilmiş dosya ile 931 ekleme ve 34 silme
  1. 1 0
      android_bed/build.gradle
  2. 29 4
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/CallingbedActivationActivity.kt
  3. 57 6
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/CallingbedActivity.kt
  4. 4 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/CallingbedDormitoryActivity.kt
  5. 4 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/CallingbedMomActivity.kt
  6. 4 0
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/OfflineCallingbedActivity.kt
  7. 13 9
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/TextActivity.kt
  8. 1 1
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/fragment/NurseFragment.kt
  9. 11 4
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/hardware/imp/A133HardTools.java
  10. 2 2
      android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/SleepService.java
  11. 25 0
      android_bed/src/main/res/layout-land/callingbed_test_main.xml
  12. 27 2
      android_bed/src/main/res/layout/callingbed_test_main.xml
  13. 333 0
      bedlib/src/main/java/serialporttest/utils/SerialPortNfcUtil.java
  14. 3 3
      bedlib/src/main/java/serialporttest/utils/SerialPortUtilSleep.java
  15. 278 0
      bedlib/src/main/java/serialporttest/utils/YBytes.java
  16. 4 1
      build.gradle
  17. 4 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/api/BedDeviceApi.kt
  18. 1 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/common/Constant.java
  19. 5 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/contract/callingbed/BedCallingbedActivityContract.kt
  20. 15 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/presenter/callingbed/BedCallingbedActivityPresenter.kt
  21. 30 2
      middleware/src/main/code/com/wdkl/ncs/android/middleware/model/dos/ClerkDO.java
  22. 80 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/model/vo/ClerkVO.java

+ 1 - 0
android_bed/build.gradle

@@ -44,6 +44,7 @@ android {
         buildConfigField 'String', 'device_type', "\"${project.rootProject.ext.device_type}\""
         buildConfigField 'String', 'sleep_type', "\"${project.rootProject.ext.sleep_type}\""
         buildConfigField 'String', 'feature_type', "\"${project.rootProject.ext.feature_type}\""
+        buildConfigField 'String', 'serial_nfc', "\"${project.rootProject.ext.serial_nfc}\""
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
 
     }

+ 29 - 4
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/CallingbedActivationActivity.kt

@@ -55,10 +55,7 @@ import okhttp3.Request
 import org.greenrobot.eventbus.EventBus
 import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.ThreadMode
-import serialporttest.utils.SerialPortUtil
-import serialporttest.utils.SerialPortUtil433
-import serialporttest.utils.SerialPortUtilLoar
-import serialporttest.utils.StringUtils
+import serialporttest.utils.*
 import java.util.*
 import java.util.concurrent.TimeUnit
 
@@ -697,6 +694,34 @@ class CallingbedActivationActivity  : BaseActivity<CallingbedActivationPresenter
             SerialPortUtilLoar.getInstance().setOnLoarDataReceiveListener(this)
         }
 
+        if (BuildConfig.serial_nfc.toBoolean()) {
+            SerialPortNfcUtil.getInstance().setOnDataReceiveStringListener { buffer, size ->
+                try {
+                    //NFC串口数据
+                    //fe080304002fa5111286
+                    val bytes = Arrays.copyOfRange(buffer, 0, size)
+                    val receiveData: String = StringUtils.bytesToHex(bytes).toUpperCase(Locale.ROOT)
+                    Log.e(TAG, "received nfc data: $receiveData")
+
+                    if (bytes.size >= 10 && bytes[0] == 0xFE.toByte() && bytes[2] == 0x03.toByte()) {
+                        if (bytes[3] == 0x04.toByte() && bytes[4] == 0x00.toByte()) {
+                            //卡类型: MF1 S50
+                            val cardNo = Arrays.copyOfRange(bytes, 5, bytes.size - 1)
+                            val hexCardNo = StringUtils.bytesToHex(cardNo)  //.toUpperCase(Locale.ROOT)
+
+                            Log.d(TAG, "nfc hexCardNo: $hexCardNo")
+
+                            //测试模式
+                            if (Constant.isText) {
+                                EventBus.getDefault().post(MessageEvent(hexCardNo, Constant.EVENT_SERIAL_NFC_TEST_VALUE))
+                            }
+                        }
+                    }
+                } catch (e: Exception) {
+                    e.printStackTrace()
+                }
+            }
+        }
     }
 
 

+ 57 - 6
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/CallingbedActivity.kt

@@ -106,10 +106,7 @@ import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.ThreadMode
 import org.linphone.core.Call
 import org.linphone.core.TransportType
-import serialporttest.utils.SerialPortUtil
-import serialporttest.utils.SerialPortUtil433
-import serialporttest.utils.SerialPortUtilLoar
-import serialporttest.utils.StringUtils
+import serialporttest.utils.*
 import java.io.File
 import java.io.FileOutputStream
 import java.io.InputStream
@@ -403,7 +400,7 @@ class CallingbedActivity :BaseActivity<BedCallingbedActivityPresenter, Callingbe
 
         startScheduledExecutor()
 
-        AppTool.Time.delay(10000) {
+        AppTool.Time.delay(8000) {
             //检查护理状态
             Constant.inNursing = SettingConfig.getInNursing(activity)
             if (Constant.inNursing) {
@@ -411,6 +408,43 @@ class CallingbedActivity :BaseActivity<BedCallingbedActivityPresenter, Callingbe
                 val huliTime = SettingConfig.getHuliTime(activity)
                 setHuli(huliTime, false)
             }
+
+            if (BuildConfig.serial_nfc.toBoolean()) {
+                SerialPortNfcUtil.getInstance().setOnDataReceiveStringListener { buffer, size ->
+                    try {
+                        //NFC串口数据
+                        //fe080304002fa5111286
+                        val bytes = Arrays.copyOfRange(buffer, 0, size)
+                        val receiveData: String = StringUtils.bytesToHex(bytes).toUpperCase(Locale.ROOT)
+                        Log.e(TAG, "received nfc data: $receiveData")
+
+                        if (bytes.size >= 10 && bytes[0] == 0xFE.toByte() && bytes[2] == 0x03.toByte()) {
+                            if (bytes[3] == 0x04.toByte() && bytes[4] == 0x00.toByte()) {
+                                //卡类型: MF1 S50
+                                val cardNo = Arrays.copyOfRange(bytes, 5, bytes.size - 1)
+                                val hexCardNo = StringUtils.bytesToHex(cardNo)  //.toUpperCase(Locale.ROOT)
+
+                                Log.d(TAG, "nfc hexCardNo: $hexCardNo")
+
+                                if (Constant.isText) {
+                                    EventBus.getDefault().post(MessageEvent(hexCardNo, Constant.EVENT_SERIAL_NFC_TEST_VALUE))
+                                } else {
+                                    //如果当前已经在医护界面或者在护理状态则不切换
+                                    if (nurseFragment.equals(curFragment) || Constant.inNursing) {
+                                        //doing nothing
+                                    } else {
+                                        if (Constant.PART_ID != null) {
+                                            presenter.checkClerk(Constant.PART_ID, hexCardNo)
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    } catch (e: Exception) {
+                        e.printStackTrace()
+                    }
+                }
+            }
         }
     }
 
@@ -1436,6 +1470,14 @@ class CallingbedActivity :BaseActivity<BedCallingbedActivityPresenter, Callingbe
 
     }
 
+    override fun showClerk(clerk: ClerkVO) {
+        //查询到员工id
+        YhUtil.sendLanding(Constant.DEVICE_ID, clerk.passNo)
+
+        SPUtils.put(activity, Constant.YH_NO, clerk.passNo)
+        SPUtils.put(activity, Constant.YH_NAME, clerk.clerkName)
+    }
+
     fun startToActivity(intent: Intent) {
         AppTool.Setting.startNewActivity(this@CallingbedActivity, intent)
     }
@@ -3677,13 +3719,22 @@ class CallingbedActivity :BaseActivity<BedCallingbedActivityPresenter, Callingbe
 
     override fun Readsuccessfully(id: String) {
         //出现医护界面
-        if (!nwFragment.equals(curFragment)) {
+        /*if (!nwFragment.equals(curFragment)) {
             val bundle = Bundle()
             bundle.putString("nfc_id", id)
             bundle.putString("type", "0")
             val fragment = NursingWorkFragment()
             fragment.arguments = bundle
             switchFragment(R.id.callingbed_main_frame, fragment, nwFragment)
+        }*/
+
+        //如果当前已经在医护界面或者在护理状态则不切换
+        if (nurseFragment.equals(curFragment) || Constant.inNursing) {
+            //doing nothing
+        } else {
+            if (Constant.PART_ID != null) {
+                presenter.checkClerk(Constant.PART_ID, id)
+            }
         }
     }
 

+ 4 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/CallingbedDormitoryActivity.kt

@@ -845,6 +845,10 @@ class CallingbedDormitoryActivity :BaseActivity<BedCallingbedActivityPresenter,
 
     }
 
+    override fun showClerk(clerk: ClerkVO) {
+
+    }
+
     fun startToActivity(intent: Intent) {
         AppTool.Setting.startNewActivity(this@CallingbedDormitoryActivity, intent)
     }

+ 4 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/CallingbedMomActivity.kt

@@ -971,6 +971,10 @@ class CallingbedMomActivity :BaseActivity<BedCallingbedActivityPresenter, Callin
 
     }
 
+    override fun showClerk(clerk: ClerkVO) {
+
+    }
+
     private fun startSipService() {
         //val intent = Intent(BaseApplication.appContext, SipService::class.java)
         //startService(intent)

+ 4 - 0
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/OfflineCallingbedActivity.kt

@@ -492,6 +492,10 @@ class OfflineCallingbedActivity :BaseActivity<BedCallingbedActivityPresenter, Ca
 
     }
 
+    override fun showClerk(clerk: ClerkVO) {
+
+    }
+
     fun startToActivity(intent: Intent) {
         AppTool.Setting.startNewActivity(this@OfflineCallingbedActivity, intent)
     }

+ 13 - 9
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/activity/TextActivity.kt

@@ -63,7 +63,6 @@ class TextActivity : BaseActivity<BedTextActivityPresenter, CallingbedTestMainBi
         showui()
         RecordHelper.getInstance().init()
         if (SettingConfig.getSipEnabled(this)) {
-            ll_sip_config_view.visibility = View.VISIBLE
             linphoneManager = LinphoneManager.getInstance(BaseApplication.appContext)
             LinphoneManager.sipTesting = true
 
@@ -73,8 +72,6 @@ class TextActivity : BaseActivity<BedTextActivityPresenter, CallingbedTestMainBi
             }else{
                 password_ed.hint = core.identity
             }
-        } else {
-            ll_sip_config_view.visibility = View.GONE
         }
 
         //摄像头调用  暂无
@@ -84,13 +81,17 @@ class TextActivity : BaseActivity<BedTextActivityPresenter, CallingbedTestMainBi
     override fun bindEvent() {
         //  sip呼叫测试  门口机暂时没有
         text_call_button.setOnClickListener {
-            val sipNo = password_ed.text
-            if (sipNo.equals("")){
-                Toast.makeText(this, "sip no must input", Toast.LENGTH_SHORT).show()
-                return@setOnClickListener
-            }
+            if (SettingConfig.getSipEnabled(this)) {
+                val sipNo = password_ed.text
+                if (sipNo.equals("")) {
+                    Toast.makeText(this, "sip account must input", Toast.LENGTH_SHORT).show()
+                    return@setOnClickListener
+                }
 
-            linphoneManager?.startCall(sipNo.toString(), false)
+                linphoneManager?.startCall(sipNo.toString(), false)
+            } else {
+                showMessage("sip disabled!")
+            }
         }
 
         lycs_button.setOnClickListener {
@@ -329,6 +330,9 @@ class TextActivity : BaseActivity<BedTextActivityPresenter, CallingbedTestMainBi
             val keyValue = messageEvent.message as String
             tv_serial_key_value.setText(keyValue)
             //showMessage("serial key value: $keyValue")
+        } else if (Constant.EVENT_SERIAL_NFC_TEST_VALUE == messageEvent.type) {
+            val nfcData = messageEvent.message as String
+            tv_serial_nfc_data.setText(nfcData)
         } else if (Constant.EVENT_FINISHh == messageEvent.type){
                finish()
         }

+ 1 - 1
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/fragment/NurseFragment.kt

@@ -58,7 +58,7 @@ class NurseFragment : BaseFragment<NurseFragmentPresenter, CallingbedNurseMainBi
     }
     //点击事件
     override fun bindEvent() {
-           //退出医护
+        //退出医护
         nurse_main_bt.setOnClickListener {
             YhUtil.sendExitLanding(Constant.DEVICE_ID, id.toInt())
             (activity as CallingbedActivity).BackMain()

+ 11 - 4
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/hardware/imp/A133HardTools.java

@@ -29,6 +29,7 @@ import java.util.List;
 
 import kotlin.Unit;
 import kotlin.jvm.functions.Function0;
+import serialporttest.utils.SerialPortNfcUtil;
 import serialporttest.utils.SerialPortUtil;
 import serialporttest.utils.SerialPortUtil433;
 import serialporttest.utils.SerialPortUtilLoar;
@@ -55,9 +56,15 @@ public class A133HardTools extends HardTools {
         if (Boolean.parseBoolean(BuildConfig.open_sleep)){
             SettingConfig.setSLEEPGatewayOn(callingbedActivationActivity, true);
         }
+
         if (BuildConfig.device_type.equals("4")){
             SerialPortUtilLoar.getInstance().openSerialPort();
-        }else {
+        } else if (Boolean.parseBoolean(BuildConfig.serial_nfc)) {
+            new Thread(() -> {
+                //NFC serial port
+                SerialPortNfcUtil.getInstance().openSerialPort();
+            }).start();
+        } else {
             if (Boolean.parseBoolean(BuildConfig.open_433)){
                 SerialPortUtil433.getInstance().openSerialPort();
                 SettingConfig.set433GatewayOn(callingbedActivationActivity, true);
@@ -71,11 +78,11 @@ public class A133HardTools extends HardTools {
         SerialPortUtil.getInstance().closeSerialPort();
         if (BuildConfig.device_type.equals("4")){
             SerialPortUtilLoar.getInstance().closeSerialPort();
-        }else {
+        } else  if (Boolean.parseBoolean(BuildConfig.serial_nfc)) {
+            SerialPortNfcUtil.getInstance().closeSerialPort();
+        } else {
             SerialPortUtil433.getInstance().closeSerialPort();
         }
-
-
     }
 
     @Override

+ 2 - 2
android_bed/src/main/java/com/wdkl/app/ncs/callingbed/sleep/SleepService.java

@@ -107,10 +107,10 @@ public class SleepService extends Service implements BeaconConsumer, SleepSocket
         notificationUtil = new NotificationUtil(this);
         startForeground(notificationUtil.notificationId, notificationUtil.getBuilder().build());
 
+        //0 4g 1 串口 2 蓝牙 3 wifi
         if (BuildConfig.sleep_type.equals("1")){
-            //0 4g 1 串口 2 蓝牙 3 wifi
             SerialPattern();
-        }else  if (BuildConfig.sleep_type.equals("3")){
+        } else  if (BuildConfig.sleep_type.equals("3")){
             Log.i(TAG, "连接ws---------------------");
             BtPattern();
         }

+ 25 - 0
android_bed/src/main/res/layout-land/callingbed_test_main.xml

@@ -101,6 +101,31 @@
                         android:textStyle="bold" />
                 </LinearLayout>
 
+                <LinearLayout
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="10dp">
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:gravity="center"
+                        android:text="NFC data:"
+                        android:textColor="#369890"
+                        android:textSize="@dimen/font_size_18"
+                        android:textStyle="bold" />
+
+                    <TextView
+                        android:id="@+id/tv_serial_nfc_data"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginLeft="10dp"
+                        android:gravity="center"
+                        android:textColor="#D81B60"
+                        android:textSize="@dimen/font_size_22"
+                        android:textStyle="bold" />
+                </LinearLayout>
+
             </LinearLayout>
 
             <ScrollView

+ 27 - 2
android_bed/src/main/res/layout/callingbed_test_main.xml

@@ -32,7 +32,7 @@
                 <ImageView
                     android:layout_width="@dimen/d88"
                     android:layout_height="@dimen/d88"
-                    android:layout_marginTop="@dimen/d66"
+                    android:layout_marginTop="@dimen/d20"
                     android:src="@mipmap/hedimg" />
 
                 <TextView
@@ -81,7 +81,7 @@
                 <LinearLayout
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_marginTop="20dp">
+                    android:layout_marginTop="10dp">
 
                     <TextView
                         android:layout_width="wrap_content"
@@ -103,6 +103,31 @@
                         android:textStyle="bold" />
                 </LinearLayout>
 
+                <LinearLayout
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="10dp">
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:gravity="center"
+                        android:text="NFC data:"
+                        android:textColor="#369890"
+                        android:textSize="@dimen/font_size_18"
+                        android:textStyle="bold" />
+
+                    <TextView
+                        android:id="@+id/tv_serial_nfc_data"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginLeft="10dp"
+                        android:gravity="center"
+                        android:textColor="#D81B60"
+                        android:textSize="@dimen/font_size_22"
+                        android:textStyle="bold" />
+                </LinearLayout>
+
             </LinearLayout>
 
             <ScrollView

+ 333 - 0
bedlib/src/main/java/serialporttest/utils/SerialPortNfcUtil.java

@@ -0,0 +1,333 @@
+package serialporttest.utils;
+
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.concurrent.TimeoutException;
+
+import android_serialport_api.SerialPort;
+
+public class SerialPortNfcUtil {
+    private String TAG = "SerialPortNfcUtil";
+
+    public SerialPort serialPort = null;
+    public InputStream inputStream = null;
+    public OutputStream outputStream = null;
+
+    private ISerialPortNfcListener serialPortNfcListener = null;
+    public boolean isOpenSerialPortUtil = false;
+
+    public Thread receiveThread = null;
+
+    public static SerialPortNfcUtil instance = null;
+
+    public SerialPortNfcUtil() {
+    }
+
+    public static SerialPortNfcUtil getInstance() {
+        if (instance == null) {
+            synchronized (SerialPortNfcUtil.class) {
+                if (instance == null) {
+                    instance = new SerialPortNfcUtil();
+                }
+            }
+        }
+        return instance;
+    }
+
+    /**
+     * 打开串口的方法
+     */
+    public void openSerialPort() {
+
+        Log.i(TAG, "打开NFC串口7");
+        try {
+            serialPort = new SerialPort();
+            serialPort.setCallback(new SerialPort.Callback() {
+                @Override
+                public void onOpen(boolean success) {
+                    //获取打开的串口中的输入输出流,以便于串口数据的收发
+                    inputStream = serialPort.getInputStream();
+                    outputStream = serialPort.getOutputStream();
+                    isOpenSerialPortUtil = true;
+                    Log.i(TAG, "open nfc serialPort7 success...");
+                    receiveSerialPort();
+                }
+            });
+            serialPort.open(new File("/dev/ttyS7"), 115200, 0);
+        } catch (Exception e) {
+            e.printStackTrace();
+            Log.e(TAG, "open nfc serialPort7 failed...");
+        }
+    }
+
+    /**
+     * 接收串口数据的方法
+     */
+    public void receiveSerialPort() {
+        if (receiveThread != null)
+            return;
+
+        Log.e(TAG, "NFC接收数据线程...");
+
+        receiveThread = new Thread() {
+            @Override
+            public void run() {
+                while (isOpenSerialPortUtil) {
+                    /*try {
+                        Thread.sleep(150);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+
+                    int size;
+                    try {
+                        byte[] buffer = new byte[64];
+                        if (inputStream == null) {
+                            return;
+                        }
+
+                        if(inputStream.available()>0) {
+                            size = inputStream.read(buffer);
+                            Log.e(TAG, "nfc data byte: " + Arrays.toString(buffer) + ", size: " + size);
+                            if (size > 0) {
+                                if (serialPortNfcListener != null) {
+                                    serialPortNfcListener.onNfcData(buffer, size);
+                                }
+                            }
+                        }
+
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                        return;
+                    }*/
+
+
+                    while (!Thread.currentThread().isInterrupted()) {
+                        try {
+                            //如果可读取消息为0,就不继续。防止InputStream.read阻塞
+                            if (inputStream.available() == 0) {
+                                SystemClock.sleep(10);
+                                continue;
+                            }
+
+                            byte[] bytes = readTime(inputStream, 1, 1000).getBytes();
+                            //无数据不返回
+                            if (bytes.length != 0) {
+                                if (serialPortNfcListener != null) {
+                                    serialPortNfcListener.onNfcData(bytes, bytes.length);
+                                }
+
+                                String receiveData = StringUtils.bytesToHex(bytes).toUpperCase(Locale.ROOT);
+                                Log.e(TAG, "received nfc data: " + receiveData);
+                            }
+
+
+                        } catch (Throwable e) {
+                            Log.e(TAG, "读取线程异常", e);
+                        }
+                    }
+                }
+            }
+        };
+        //启动接收线程
+        receiveThread.start();
+    }
+
+    /**
+     * 只读一次,读取到就返回,读取不到就一直等
+     *
+     * @param inputStream inputStream
+     * @return byte[]
+     * @throws Exception Exception
+     */
+    @Deprecated
+    public static byte[] readOnce(InputStream inputStream) throws Exception {
+        return readOnce(inputStream, Long.MAX_VALUE);
+    }
+
+    /**
+     * 只读一次,读取到就返回。读取不到,一直等直到超时,如果超时则向上抛异常
+     *
+     * @param inputStream inputStream
+     * @param timeOut     超时毫秒
+     * @return byte[]
+     * @throws Exception Exception
+     */
+    public static byte[] readOnce(InputStream inputStream, long timeOut) throws Exception {
+        long startTime = System.currentTimeMillis();
+        int count = 0;
+        while (count == 0 && System.currentTimeMillis() - startTime < timeOut)
+            count = inputStream.available();//获取真正长度
+        if (System.currentTimeMillis() - startTime >= timeOut) {
+            throw new TimeoutException("读取超时");
+        }
+        byte[] bytes = new byte[count];
+        // 一定要读取count个数据,如果inputStream.read(bytes);可能读不完
+        int readCount = 0; // 已经成功读取的字节的个数
+        while (readCount < count)
+            readCount += inputStream.read(bytes, readCount, count - readCount);
+        return bytes;
+    }
+
+    /**
+     * 读取inputStream数据到YBytes,一直不停组包,每次组包时间maxGroupTime,如果maxGroupTime内没数据,就返回。
+     *
+     * @param inputStream  inputStream
+     * @param maxGroupTime 最大组包时间,如果这个时间内有数据,就一直组包。如果这个时间都没数据,就返回。
+     * @return YBytes
+     * @throws Exception Exception
+     */
+    @Deprecated
+    public static YBytes readTime(InputStream inputStream, int maxGroupTime) throws Exception {
+        return readTime(inputStream, maxGroupTime, Integer.MAX_VALUE);
+    }
+
+    /**
+     * 读取inputStream数据到YBytes,一直不停组包,每次组包时间maxGroupTime,如果一直有数据,不超过maxTime。
+     *
+     * @param inputStream  inputStream
+     * @param maxGroupTime 最大组包时间,如果这个时间内有数据,就一直组包。如果这个时间都没数据,就返回。
+     * @param maxTime      最多读取这么长时间
+     * @return YBytes
+     * @throws Exception Exception
+     */
+    public static YBytes readTime(InputStream inputStream, int maxGroupTime, int maxTime) throws Exception {
+        final YBytes bytes = new YBytes();
+        long startTime = System.currentTimeMillis();//开始时间
+        long groupTime;//运行时间
+        int i = 0;//第几次组包
+        int count = inputStream.available();//可读取多少字节内容
+        do {
+            byte[] newBytes = new byte[1024];
+            int newSize = inputStream.read(newBytes, 0, count);
+            if (newSize > 0) {
+                bytes.addByte(newBytes, newSize);
+                log("第" + (++i) + "次组包后长度:" + bytes.getBytes().length + ",\t已耗时:" + (System.currentTimeMillis() - startTime));
+            }
+            SystemClock.sleep(1);
+            count = inputStream.available();
+            groupTime = System.currentTimeMillis();
+            //如果读取长度为0,那么休息1毫秒继续读取,如果在maxGroupTime时间内都没有数据,那么就退出循环,或者超过maxTime
+            while (count == 0 && System.currentTimeMillis() - groupTime <= maxGroupTime && System.currentTimeMillis() - startTime <= maxTime) {
+                SystemClock.sleep(1);
+                count = inputStream.available();
+            }
+        } while (System.currentTimeMillis() - groupTime <= maxGroupTime && System.currentTimeMillis() - startTime <= maxTime);
+        return bytes;
+    }
+
+    /**
+     * 读取inputStream数据到YBytes,一直不停组包,至少读取时间:leastTime。但是期间读取长度达到minReadLength,立即返回。
+     *
+     * @param inputStream inputStream
+     * @param maxTime     最多读取这么长时间
+     * @param minLength   至少读取长度,只要读取长度大于等于minLength,直接返回,最多读取maxTime时间
+     * @return YBytes
+     * @throws Exception Exception
+     */
+    public static YBytes readLength(final InputStream inputStream, final int minLength, final int maxTime) throws Exception {
+        final YBytes bytes = new YBytes();
+        long startTime = System.currentTimeMillis();
+        int i = 0;
+        while (bytes.getBytes().length < minLength && System.currentTimeMillis() - startTime < maxTime) {
+            //如果可读取消息为0,就不继续。防止InputStream.read阻塞
+            if (inputStream.available() == 0) {
+                SystemClock.sleep(1);
+                continue;
+            }
+            byte[] newBytes = new byte[Math.max(minLength, 1024)];
+            int newSize = inputStream.read(newBytes, 0, inputStream.available());
+            if (newSize > 0) {
+                bytes.addByte(newBytes, newSize);
+                log("第" + (++i) + "次组包后长度:" + bytes.getBytes().length + ",\t目标长度:" + minLength + ",\t已耗时:" + (System.currentTimeMillis() - startTime) + "ms,\t超时时间:" + maxTime + "ms");
+            }
+        }
+        if (System.currentTimeMillis() - startTime >= maxTime)
+            log("超时返回,超时时间:" + maxTime + "ms");
+        return bytes;
+    }
+
+    private static void log(String string) {
+        Log.i("Serial", string);
+    }
+
+
+    /**
+     * 关闭串口的方法
+     * 关闭串口中的输入输出流
+     * 然后将flag的值设为flag,终止接收数据线程
+     */
+    public void closeSerialPort() {
+        Log.i(TAG, "关闭串口");
+        try {
+            if (inputStream != null) {
+                inputStream.close();
+            }
+            if (outputStream != null) {
+                outputStream.close();
+            }
+            if (receiveThread != null && receiveThread.isAlive()) {
+                receiveThread.interrupt();
+                receiveThread = null;
+            }
+            isOpenSerialPortUtil = false;
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    //MF1卡读块(待验证)
+    public void readTag() {
+        byte[] cmd = {(byte)0x00, (byte)0x00, (byte)0x0A, (byte)0x04, (byte)0x02, (byte)0x01,
+                (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x0D};
+
+        sendBytes(cmd);
+    }
+
+    /**
+     * 发送串口数据的方法
+     *
+     * @param command 要发送的数据
+     */
+    private void send(String command) {
+        try {
+            if (isOpenSerialPortUtil) {
+                byte[] sendData = command.getBytes();
+                outputStream.write(sendData);
+                Log.i(TAG, "NFC串口数据发送成功: " + command);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+            Log.i(TAG, "NFC串口数据发送失败");
+        }
+    }
+
+    private void sendBytes(byte[] cmd) {
+        try {
+            if (isOpenSerialPortUtil) {
+                outputStream.write(cmd);
+                Log.i(TAG, "NFC串口数据发送成功");
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+            Log.i(TAG, "NFC串口数据发送失败");
+        }
+    }
+
+    public void setOnDataReceiveStringListener(ISerialPortNfcListener listener) {
+        serialPortNfcListener = listener;
+    }
+
+    public interface ISerialPortNfcListener {
+        void onNfcData(final byte[] buffer, final int size);
+    }
+
+}

+ 3 - 3
bedlib/src/main/java/serialporttest/utils/SerialPortUtilSleep.java

@@ -41,7 +41,7 @@ public class SerialPortUtilSleep {
      * 打开串口的方法
      */
     public void openSerialPort() {
-        Log.i(TAG, "打开串口0");
+        Log.i(TAG, "打开串口2");
         try {
             SleepserialPort = new SerialPort();
             SleepserialPort.setCallback(new SerialPort.Callback() {
@@ -51,14 +51,14 @@ public class SerialPortUtilSleep {
                     SleepinputStream = SleepserialPort.getInputStream();
                     SleepoutputStream = SleepserialPort.getOutputStream();
                     isOpenSerialPortUtil = true;
-                    Log.i(TAG, "open openSerialPort0 success...");
+                    Log.i(TAG, "open openSerialPort2 success...");
                     receiveSerialPort();
                 }
             });
             SleepserialPort.open(new File("/dev/ttyS2"), 115200, 0);
         } catch (Exception e) {
             e.printStackTrace();
-            Log.e(TAG, "open openSerialPort0 failed...");
+            Log.e(TAG, "open openSerialPort2 failed...");
         }
     }
 

+ 278 - 0
bedlib/src/main/java/serialporttest/utils/YBytes.java

@@ -0,0 +1,278 @@
+package serialporttest.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * byte拼接类
+ *
+ */
+@SuppressWarnings("unused")
+public class YBytes {
+    private byte[] bytes;
+
+    /**
+     * 构造函数,创建一个长度为0的byte数组
+     */
+    public YBytes() {
+        bytes = new byte[0];
+    }
+
+    /**
+     * 构造函数,创建一个长度为i的byte数组
+     *
+     * @param i byte[]长度
+     */
+    public YBytes(int i) {
+        bytes = new byte[i];
+    }
+
+    /**
+     * 构造函数创建一个初始的byte数组
+     *
+     * @param b 初始数组
+     */
+    public YBytes(byte[] b) {
+        this.bytes = new byte[b.length];
+        System.arraycopy(b, 0, this.bytes, 0, b.length);
+    }
+
+    /**
+     * 在byte数组末尾添加一个byte
+     *
+     * @param b b
+     * @return YBytes
+     */
+    public YBytes addByte(byte b) {
+        byte[] temp = new byte[bytes.length + 1];
+        System.arraycopy(bytes, 0, temp, 0, bytes.length);
+        temp[temp.length - 1] = b;
+        bytes = temp;
+        return this;
+    }
+
+    /**
+     * 在byte数组末尾添加一个byte[]
+     *
+     * @param bs bs
+     * @return YBytes
+     */
+    public YBytes addByte(byte[] bs) {
+        byte[] temp = new byte[bytes.length + bs.length];
+        System.arraycopy(bytes, 0, temp, 0, bytes.length);
+        System.arraycopy(bs, 0, temp, bytes.length, bs.length);
+        bytes = temp;
+        return this;
+    }
+
+    /**
+     * 在byte数组末尾添加一个byte[],给定添加的长度
+     *
+     * @param bs     添加的数组
+     * @param length 添加的长度
+     * @return Bytes
+     */
+    public YBytes addByte(byte[] bs, int length) {
+        byte[] temp = new byte[bytes.length + length];
+        System.arraycopy(bytes, 0, temp, 0, bytes.length);
+        System.arraycopy(bs, 0, temp, bytes.length, length);
+        bytes = temp;
+        return this;
+    }
+
+    /**
+     * 在byte数组末尾添加一个byte[],给定添加的长度
+     *
+     * @param bs     添加的数组
+     * @param start  开始位置
+     * @param length 添加的长度
+     * @return Bytes
+     */
+    public YBytes addByte(byte[] bs, int start, int length) {
+        byte[] temp = new byte[bytes.length + length];
+        System.arraycopy(bytes, 0, temp, 0, bytes.length);
+        System.arraycopy(bs, start, temp, bytes.length, length);
+        bytes = temp;
+        return this;
+    }
+
+    /**
+     * 在byte数组末尾添加一组Byte
+     *
+     * @param bs bs
+     * @return YBytes
+     */
+    public YBytes addByte(List<Byte> bs) {
+        byte[] temp = new byte[bytes.length + bs.size()];
+        System.arraycopy(bytes, 0, temp, 0, bytes.length);
+        for (int i = 0; i < bs.size(); i++) {
+            temp[bytes.length + i] = bs.get(i);
+        }
+        bytes = temp;
+        return this;
+    }
+
+    /**
+     * 在byte数组末尾添加一个List
+     *
+     * @param bs     添加的集合
+     * @param length 添加的长度
+     * @return Bytes
+     */
+    public YBytes addByte(List<Byte> bs, int length) {
+        byte[] temp = new byte[bytes.length + length];
+        System.arraycopy(bytes, 0, temp, 0, bytes.length);
+        for (int i = 0; i < length; i++) {
+            temp[bytes.length + i] = bs.get(i);
+        }
+        bytes = temp;
+        return this;
+    }
+
+    /**
+     * 在byte数组末尾添加一个List
+     *
+     * @param bs     添加的集合
+     * @param start  开始位置
+     * @param length 添加的长度
+     * @return Bytes
+     */
+    public YBytes addByte(List<Byte> bs, int start, int length) {
+        byte[] temp = new byte[bytes.length + length];
+        System.arraycopy(bytes, 0, temp, 0, bytes.length);
+        for (int i = 0; i < length; i++) {
+            temp[bytes.length + i] = bs.get(i + start);
+        }
+        bytes = temp;
+        return this;
+    }
+
+    /**
+     * 修改byte数组中一位的值为byte
+     *
+     * @param b     数据
+     * @param index 位置
+     * @return YBytes
+     */
+    public YBytes changeByte(byte b, int index) {
+        if (index >= 0 && index < bytes.length) {
+            bytes[index] = b;
+        }
+        return this;
+    }
+
+    /**
+     * 修改byte数组中第index位起值为b
+     *
+     * @param b     数据
+     * @param index 位置
+     * @return YBytes
+     */
+    public YBytes changeByte(byte[] b, int index) {
+        return changeByte(b, index, index + b.length);
+    }
+
+    /**
+     * 修改byte数组中第start位起值为b,连续修改length位
+     *
+     * @param b      数据
+     * @param start  起始位置
+     * @param length 结束位置
+     * @return YBytes
+     */
+    public YBytes changeByte(byte[] b, int start, int length) {
+        if (start >= 0 && length > 0) {
+            for (int i = 0; i < length; i++) {
+                if (start + i < bytes.length) {
+                    bytes[start + i] = b[i];
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * 修改byte数组中第index位起值为b
+     *
+     * @param b     数据
+     * @param index 位置
+     * @return YBytes
+     */
+    public YBytes changeByte(List<Byte> b, int index) {
+        return changeByte(b, index,  b.size());
+    }
+
+    /**
+     * 修改byte数组中第start位起值为b,连续修改length位
+     *
+     * @param b      数据
+     * @param start  起始位置
+     * @param length 结束位置
+     * @return YBytes
+     */
+    public YBytes changeByte(List<Byte> b, int start, int length) {
+        if (start >= 0 && length > 0) {
+            for (int i = 0; i < length; i++) {
+                if (start + i < bytes.length) {
+                    bytes[start + i] = b.get(i);
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * 替换bytes数组
+     *
+     * @param bytes bytes
+     */
+    public void setBytes(byte[] bytes) {
+        this.bytes = bytes;
+    }
+
+    /**
+     * 拆分byte数组为多个byte数组
+     *
+     * @param bytes  需要拆分的数组
+     * @param length 每组最大长度
+     * @return 最终拆分的数据
+     */
+    public static List<byte[]> split(byte[] bytes, int length) {
+        List<byte[]> list = new ArrayList<>();
+        int count = 0;//统计已经发送长度
+        while (true) {
+            //剩余长度
+            int sy = bytes.length - count;
+            //如果剩余长度小于等于0,说明发送完成
+            if (sy <= 0) break;
+            //如果剩余长度大于每次写入长度,就写入对应长度,如果不大于就写入剩余长度
+            byte[] current = new byte[Math.min(sy, length)];
+            //数组copy
+            System.arraycopy(bytes, count, current, 0, current.length);
+            //写入
+            list.add(current);
+            //统计已经发送长度
+            count += current.length;
+        }
+        return list;
+    }
+
+    /**
+     * 拆分byte数组为多个byte数组
+     *
+     * @param length 每组最大长度
+     * @return 最终拆分的数据
+     */
+    public List<byte[]> split(int length) {
+        return split(bytes, length);
+    }
+
+    /**
+     * 获取bytes数组
+     *
+     * @return byte[]
+     */
+    public byte[] getBytes() {
+        return bytes;
+    }
+}

+ 4 - 1
build.gradle

@@ -54,7 +54,7 @@ buildscript {
     ext.android_visiting = false
 
     //养老版
-    ext.yanglao = false
+    ext.yanglao = true
 
     //是否月子版
     ext.is_mom = false
@@ -67,6 +67,9 @@ buildscript {
     //分机-433
     ext.open_433 = false
 
+    //NFC串口2
+    ext.serial_nfc = true
+
     //设备类型  0 医院 1 月子中心 2 养老院 3 公寓 4 宿舍
     ext.device_type = 0
 

+ 4 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/api/BedDeviceApi.kt

@@ -134,4 +134,8 @@ interface BedDeviceApi {
     //某个科室的模版消息
     @GET("/template-message-tpl/template-message/{part_id}")
     fun message_template_tpl(@Path("part_id") part_id:Int): Observable<ResponseBody>
+
+    //通过卡号获取员工信息
+    @GET("/deviceRoom/get_clerk_by_part_id_and_pass_no/{part_id}/{pass_no}")
+    fun getClerkByNo(@Path("part_id") partId: Int, @Path("pass_no") passNo: String): Observable<ResponseBody>
 }

+ 1 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/common/Constant.java

@@ -659,4 +659,5 @@ public class Constant {
     public static final int EVENT_WIFI_ENABLE = 0x221;
     public static final int EVENT_NETWORK_CHANGE = 0x222;
     public static final int EVENT_SERIAL_TEST_VALUE = 0x223;
+    public static final int EVENT_SERIAL_NFC_TEST_VALUE = 0x224;
 }

+ 5 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/contract/callingbed/BedCallingbedActivityContract.kt

@@ -38,6 +38,8 @@ interface BedCallingbedActivityContract {
 
         fun setDevicesList(advices: ArrayList<DeviceLinVo>)
 
+        fun showClerk(clerk: ClerkVO)
+
         fun onNoNet()
     }
 
@@ -82,5 +84,8 @@ interface BedCallingbedActivityContract {
          * 加载可通话电话号码白名单
          */
         fun getWhiteList(deviceId: Int)
+
+        //查询员工
+        fun checkClerk(partId: Int, passNo: String)
     }
 }

+ 15 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/presenter/callingbed/BedCallingbedActivityPresenter.kt

@@ -75,6 +75,10 @@ class BedCallingbedActivityPresenter @Inject constructor() :RxPresenter<BedCalli
                     providerView().showEmergencyInfo(result)
                 }
 
+                is ClerkVO -> {
+                    providerView().showClerk(result)
+                }
+
                 is List<*> ->{
                     providerView().loadRoles(result as List<RoleDO>)
                 }
@@ -321,4 +325,15 @@ class BedCallingbedActivityPresenter @Inject constructor() :RxPresenter<BedCalli
             }.compose(ThreadFromUtils.defaultSchedulers())
             .subscribe(whiteListObserver)
     }
+
+    override fun checkClerk(partId: Int, passNo: String) {
+        bedDeviceApi.getClerkByNo(partId, passNo)
+            .map {
+                val gson = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create()
+                val clerkVO = gson.fromJson(it.getJsonString(), ClerkVO::class.java)
+                return@map clerkVO
+            }
+            .compose(ThreadFromUtils.defaultSchedulers())
+            .subscribe(observer)
+    }
 }

+ 30 - 2
middleware/src/main/code/com/wdkl/ncs/android/middleware/model/dos/ClerkDO.java

@@ -2,8 +2,6 @@ package com.wdkl.ncs.android.middleware.model.dos;
 
 import com.fasterxml.jackson.databind.PropertyNamingStrategy;
 import com.fasterxml.jackson.databind.annotation.JsonNaming;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
 import com.wdkl.ncs.android.middleware.model.annotation.Column;
 import com.wdkl.ncs.android.middleware.model.annotation.Id;
 import com.wdkl.ncs.android.middleware.model.annotation.PrimaryKeyField;
@@ -11,6 +9,9 @@ import com.wdkl.ncs.android.middleware.model.annotation.Table;
 
 import java.io.Serializable;
 
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
 @Table(name = "ncs_clerk")
 @ApiModel
 @JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class)
@@ -21,6 +22,7 @@ public class ClerkDO implements Serializable {
      */
     @Column(name = "clerk_id")
     @ApiModelProperty(value = "人员id", required = false)
+    @Id(name = "clerk_id")
     private Integer clerkId;
     /**
      * 会员id
@@ -46,6 +48,10 @@ public class ClerkDO implements Serializable {
     @Column(name = "role_id")
     @ApiModelProperty(value = "权限id,可以确定为医生、护士、护工,主任医生、护士长", required = false)
     private Integer roleId;
+
+    @Column(name = "role_name")
+    @ApiModelProperty(value = "角色名称,医生、护士、护工,主任医生、护士长", required = false)
+    private String roleName;
     /**
      * 店员状态,0为禁用,1为正常
      */
@@ -95,6 +101,13 @@ public class ClerkDO implements Serializable {
     @ApiModelProperty(value = "null", required = false)
     private String hisPartKeyval;
 
+    /**
+     * 上属id
+     */
+    @Column(name = "parent_id")
+    @ApiModelProperty(value = "上属id", required = false)
+    private Integer parentId;
+
 
     @PrimaryKeyField
     public Integer getClerkId() {
@@ -213,4 +226,19 @@ public class ClerkDO implements Serializable {
         this.hisPartKeyval = hisPartKeyval;
     }
 
+    public Integer getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(Integer parentId) {
+        this.parentId = parentId;
+    }
+
+    public String getRoleName() {
+        return roleName;
+    }
+
+    public void setRoleName(String roleName) {
+        this.roleName = roleName;
+    }
 }

+ 80 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/model/vo/ClerkVO.java

@@ -0,0 +1,80 @@
+package com.wdkl.ncs.android.middleware.model.vo;
+
+import com.wdkl.ncs.android.middleware.model.dos.ClerkDO;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @author wuyunfeng
+ * 2022-11-10 15:37
+ */
+public class ClerkVO extends ClerkDO {
+
+    @ApiModelProperty(value = "工号", required = false)
+    private String passNo;
+
+    @ApiModelProperty(value = "角色类型枚举值", required = false)
+    private String roleType;
+
+    @ApiModelProperty(value = "上级角色Id", required = false)
+    private Integer leaderRoleId;
+
+
+    @ApiModelProperty(value = "上级领导clerkId", required = false)
+    private Integer leaderId;
+
+
+    @ApiModelProperty(value = "上级领导姓名", required = false)
+    private String leaderName;
+
+    @ApiModelProperty(value = "作为下属职员数据时指示是否为当前上级的下级", required = false)
+    private Boolean checked;
+
+    public String getPassNo() {
+        return passNo;
+    }
+
+    public void setPassNo(String passNo) {
+        this.passNo = passNo;
+    }
+
+    public Integer getLeaderRoleId() {
+        return leaderRoleId;
+    }
+
+    public void setLeaderRoleId(Integer leaderRoleId) {
+        this.leaderRoleId = leaderRoleId;
+    }
+
+    public Integer getLeaderId() {
+        return leaderId;
+    }
+
+    public void setLeaderId(Integer leaderId) {
+        this.leaderId = leaderId;
+    }
+
+    public String getLeaderName() {
+        return leaderName;
+    }
+
+    public void setLeaderName(String leaderName) {
+        this.leaderName = leaderName;
+    }
+
+    public Boolean getChecked() {
+        return checked;
+    }
+
+    public void setChecked(Boolean checked) {
+        this.checked = checked;
+    }
+
+    public String getRoleType() {
+        return roleType;
+    }
+
+    public void setRoleType(String roleType) {
+        this.roleType = roleType;
+    }
+}