久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3513|回復: 0
收起左側

控制中心 - 筆記 -> S5PV210中ZigBee的Jni回調要點

[復制鏈接]
ID:71922 發表于 2015-1-10 20:10 | 顯示全部樓層 |閱讀模式

由于ZigBee是用USB轉串口通訊,所以需要在內核加上PL2303驅動。進入內核源碼:make menuconfig ->
                     Device Drivers ->
                           <*> USB support ->
                                   <*> USB Serial Converter support ->
                                            <*>USB Prolific 2303 Single Port Serial Driver



啟用之后重新編譯,并燒錄到FS210中。

ZigBee 模塊是通過串口通信,需要發送什么數據,只需要往串口寫入數據,里面的ZigBee即可發送數據。

Fs210 應用程序測試:app.c
-------------------------------------------------------------------------------------------------------
#include <termios.h>    //串口相關頭文件
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


流程:
    1、打開串口

    2、初始化串口

    3、讀寫串口數據

    4、關閉串口



/* 初始化串口 */
void  serial_init(int fd)
{
        struct termios options;
        tcgetattr(fd, &options);
        options.c_cflag |= ( CLOCAL | CREAD );/*input mode flag:ignore modem
        options.c_cflag &= ~CSIZE;
        options.c_cflag &= ~CRTSCTS;
        options.c_cflag |= CS8;
        options.c_cflag &= ~CSTOPB; //停止位
        options.c_iflag |= IGNPAR;        // 忽略校驗錯誤
        options.c_oflag = 0;// 無輸出模式
        options.c_lflag = 0; //本地模式禁用
        options.c_cc[VTIME] = 0;                // 50 代表5秒 5秒內沒有收到數據就返回
        options.c_cc[VMIN] = 2;                        // 代表收到2個字節就返回
        cfsetispeed(&options, B115200);
        cfsetospeed(&options, B115200);
        tcsetattr(fd,TCSANOW,&options);
}
/* 主函數 */
int main(int argc, char **args)
{
        int fd = 0;
        char a[3] = "v";
        int size = 0;
        /* 1、打開串口 */

        fd = open("/dev/ttyUSB0", O_RDWR);    // 因為該模塊是USB轉串口
        if(fd<0) return 0;
        puts("串口初始化....");


        /* 2、初始化串口 */

        serial_init(fd);


        /* 3、讀寫數據 */
        // 往串口寫數據
        write(fd, a, strlen(a));
        puts("開始接受數據");
        while(1)
        {       
                memset(a, 0, sizeof(a));
                // 從串口讀數據

                size = read(fd, a, sizeof(a));
                printf("a = %s\n", a);               
        }


        /* 4、關閉串口 */       
        close(fd);
        return 0;
}

-------------------------------------------------------------------------------------------------------

編譯腳本:Android.mk

-------------------------------------------------------------------------------------------------------

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)


LOCAL_SRC_FILES := app.c
LOCAL_MODULE := app_c


LOCAL_SHARED_LIBRARIES := \
        libcutils


LOCAL_MODULE_TAGS := optional


include $(BUILD_EXECUTABLE)

-------------------------------------------------------------------------------------------------------


Fs210作為控制中心,需要時時刻刻與M0通訊,并把數據顯示在apk應用上,需要采用JNI與上層APK交互。
需要采用回調機制,Jin回調Java的方法。可以采用NDK或獨立的Jni庫形式。
這里,我考慮到日后更新方便,就采用分離的Jni庫形式。

控制中心與節點通信的數據結構:---> 后來想想,下面這些用聯合體會更加合適一些
-------------------------------------------------------------------------------------------------------

// 節點標識  
#define M0_NUM_1        1                // M0_1 標識
#define M0_NUM_2        2                // M0_2 標識
#define M0_NUM_3        3                // M0_3 標識
#define M0_NUM_4        4                // M0_4 標識
#define M0_NUM_5        5                // M0_5 標識
#define M0_NUM_6        6                // M0_6 標識


// 命令類型
#define Get_Data                        21                  // 獲取數據
#define Set_Temp_Warning_val                22                // 設置溫度報警閥值
#define Set_Hum_Warning_val                23                // 設置濕度報警閥值
#define Set_Auto_Send                        25                // 設置主動上報數據
#define Set_NoAuto_Send                        26                // 禁止主動上報數據
                                                  
// 設備狀態
#define FAN_ON                                24                // 風扇開啟狀態
#define FAN_OFF                                25                // 風扇關閉狀態
#define BEEP_ON                                26                // 蜂鳴器開啟狀態
#define BEEP_OFF                        27                // 蜂鳴器關閉狀態


#define ZigBee_Cmd_HEAD        '$'
       
// 命令/數據 結構體
struct ZigBee_Cmd
{
        char Head;                        // 包頭 由于從串口接數據有可能第一個字節不是頭,所以需要判斷
       
        int ID;                                // 節點標識
        char CmdType;                          // 命令類型
        char TempH;                        // 溫度整數部分               
        char TempL;                        // 溫度小數部分               
        char HumH;                        // 濕度整數部分               
        char HumL;                        // 濕度小數部分
        char AdvH;                        // 電壓整數
        char AdvL;                        // 電壓小數
        signed char x;                         // 三軸傳感器 x
        signed char y;                        // 三軸傳感器 y
        signed char z;                        // 三軸傳感器 z
        int Light;                         // 亮度
        char FAN;                         // 風扇狀態       
        char BEEP;                        // 蜂鳴器狀態
        char Used;                        // CPU使用率
                       
        unsigned  int chksum;                // 校驗碼
};

-------------------------------------------------------------------------------------------------------

Jni代碼
-------------------------------------------------------------------------------------------------------

在M0中提供兩種數據發送方式:
被動獲取數據:
    APK通過Jni打開串口發送 Get_Data 指令獲取數據,M0收到指令就發送一次數據。
主動獲取數據:
    APK通過Jni打開串口發送 Set_Auto_Send 指令,M0收到指令就連續發送數據。


Jni的難點在于回調Java的方法和串口操作,如數據接收。

回調Java方法:
            需要創建新的線程,去回調Java的方法,所以需要利用全局變量將Jni的 JNIEnv *,, jobject* 保存,
        然后在線程里面使用。
實現步驟:
APK 要點:
-------------------------------------------------------------------------------------------------------
步驟1:創建一個回調方法:
        private void ZigBee_Call(int ID, char TempH, char TempL, char HumH, char HumL, char AdvH,
            char AdvL, int x, int y, int z, int Light, char FAN, char BEEP, char CPUUSed)
        {
                // 通過發送Handler消息刷新APK的GUI

                return;
        }



步驟2:聲明本地方法
        public native int ZigBee_Open();
        public native int ZigBee_Cmd(char cmd, int arg1, int arg2);
        public native int ZigBee_Close();
        public native int ZigBee_StartRevc();
        public native int ZigBee_StopRevc();

        // 添加這句是為了通過javap 命令獲取其類型簽名 獲取完后可以刪除掉

    public native void ZigBee_Call(int ID, char TempH, char TempL, char HumH, char HumL, char AdvH, char AdvL,
                        int x, int y, int z, int Light, char FAN, char BEEP, char CPUUSed);

步驟2:利用  javap -s bin\classes\com\lmx\zigbee\MainActivity 可以獲取到類型簽名 用于給Jni構建映射表
-------------------------------------------------------------------------------------------------------


Jni 回調要點:
-------------------------------------------------------------------------------------------------------

要點1:創建兩個全局變量。給線程備用。
        JavaVM *gJavaVM = NULL;

        jobject gJavaObj= NULL;



要點2:提供一個函數,或在何時的地方保存全局變量
        //注意,直接通過定義全局的JNIEnv和jobject變量,在此保存env和thiz的值是不可以在線程中使用的
        //線程不允許共用env環境變量,但是JavaVM指針是整個jvm共用的,所以可通過下面的方法保存JavaVM指針,在線程中使用
        env->GetJavaVM(&gJavaVM);
        //同理,jobject變量也不允許在線程中共用,因此需要創建全局的jobject對象在線程中訪問該對象
        gJavaObj = env->NewGlobalRef(thiz);


要點3:在線程里面通過保存的全局變量去獲取Java環境變量、獲取Java層對應類、獲取回調函數。
        //從全局的JavaVM中獲取到環境變量
        gJavaVM->AttachCurrentThread(&env, NULL);
        //獲取Java層對應的類
        jclass javaClass = env->GetObjectClass(gJavaObj);;
        //獲取Java層被回調的函數
        jmethodID javaCallback = env->GetMethodID(javaClass,"ZigBee_Call","(ICCCCCCIIIICCC)V");
        //回調Java層的函數
        env->CallVoidMethod(gJavaObj, javaCallback, ZData.ID, ZData.TempH, ZData.TempL,ZData.HumH,
        ZData.HumL, ZData.AdvH, ZData.AdvL, ZData.x, ZData.y, ZData.z, ZData.Light, ZData.FAN,
        ZData.BEEP,ZData.Used);
-------------------------------------------------------------------------------------------------------


串口操作要點:
-------------------------------------------------------------------------------------------------------

要點1:串口初始化,需要關注  .c_cc[VTIME]、.c_cc[VMIN]
void  serial_init(int fd)
{
        struct termios options;
        tcgetattr(fd, &options);
             options.c_cflag |= ( CLOCAL | CREAD );                                                                                  options.c_cflag &= ~CSIZE;
        options.c_cflag &= ~CRTSCTS;
        options.c_cflag |= CS8;                // 8位數據

        options.c_cflag &= ~CSTOPB;             //停止位

        options.c_iflag |= IGNPAR;                // 忽略校驗錯誤
        options.c_oflag = 0;                   // 無輸出模式
        options.c_lflag = 0;                   //本地模式禁用
        options.c_cc[VTIME] = 10;          // 表示 read() 超時值 50 表示 5秒后仍沒有數據則返回
        options.c_cc[VMIN] = 1;           // 表示讀到多少個字節就返回 5 表示讀完5個字節就返回
        cfsetispeed(&options, B115200);        // 設置波特率

        cfsetospeed(&options, B115200);
        tcsetattr(fd,TCSANOW,&options);
}

要點2:讀取數據的時候要注意,因為節點發送數據的時候,控制中心的ZigBee已經收到數據,而我們還未             做好準備,當ZigBee往串口寫數據寫到一半的時候,我們才做好準備收,這時候只能收到后半部分的數據,
             如果節點是一直發送數據,那么我們在收數據的時候就很可能變成 第一個數據包的后半部分與第二個數據的
             前半部分組合成一個數據包,那么解析的數據自然就不是正確的。
        //線程循環
        while(gIsThreadExit)
        {
                LOGD("ZigBee_Call...");
                memset(&ZData, 0, sizeof(struct ZigBee_Cmd));
                memset(&buf, 0, sizeof(buf));
                size = 0;
                while(size != sizeof(struct ZigBee_Cmd))  // 直至接受完一個數據包
                {
                        ret = read(fd, &rd, 1);
                        if((size == 0) && (rd != ZigBee_Cmd_HEAD)
                                continue;
                        if( ret == -1 || ret == 0)      // 若出錯則跳出循環
                                breka;
                        buf[size++] = rd;               // 若考慮優化性能,這里可以直接用結構體存,
                                                        // 存之前只需要用char*p = (char*)ZData  存的時候 *p++ = rd;
                }
                // 將數據拷貝到結構體

                memcpy(&ZData, buf, sizeof(struct ZigBee_Cmd));
                校驗數據....
                .........

                LOGD("Revc Data OK``");       
                回調Java層的函數,將數據回傳...   
                .........

        }


回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 午夜欧美 | 91亚洲精品国偷拍自产在线观看 | 99精品免费久久久久久日本 | 天堂中文字幕av | 男女黄网站 | 精品国产乱码久久久久久丨区2区 | 国产精品一区二区福利视频 | 成人三级网址 | 久久小视频 | 国产在线精品一区二区 | 国产无人区一区二区三区 | 国产一区精品在线 | 国产精品二区三区 | 免费成人高清在线视频 | 欧美激情精品久久久久久变态 | 亚洲国产一区二区三区, | 天天色天天射天天干 | 日韩精品一区二区三区中文在线 | 久久999| 精品综合在线 | 国产精品一区免费 | 久久天天躁狠狠躁夜夜躁2014 | 国产精品成人久久久久a级 久久蜜桃av一区二区天堂 | 亚洲网站在线观看 | 超碰97在线免费 | 高清人人天天夜夜曰狠狠狠狠 | 超碰在线人人 | 一级做a毛片 | 国产精品高潮呻吟久久aⅴ码 | 日韩久久久久久 | 国产精品欧美一区二区三区 | 欧美 日韩 中文 | 91在线观看| 国产精品久久久久久久久久妇女 | 久久亚 | 亚洲精品一区在线 | 国产高清免费在线 | 久久精品国产精品青草 | 黄色一级毛片 | 欧美一二三 | 精品视频一区二区三区在线观看 |