概述
QT的串口
1. 多线程
2. 子线程每隔2ms给主线程发送一个信号让主线程读取串口
3. 对重复读取的串口数据包进行了容错处理
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QDebug>
#include <QFile>
#include <QDataStream>
#include <QByteArray>
//包含自定义类的头文件
#include "mythread.h"
//一个包的长度信息
#define REAL_LEN 64//有效数据最大长度
#define HDR_LEN 8//包头长度(固定不变)
//处理照片数据的状态标志(目前没用到--留待以后扩展)
//照片数据分为三部分(begin + 有效数据 +end)
#define BEGIN 0x01//开始处理照片--接收到含有begin的包
#define END 0x02//照片数据接收完毕--接收到含有end的包
#define READING 0x03//正在处理照片数据--照片的实际有效数据
//读串口的状态标志--每个包分为两部分读取(包头+有效数据)
#define READ_HDR 0x01//读取包头
#define READ_DATA 0x02//读取有效数据
int bytesToInt(QByteArray bytes);
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
//读取指定长度的数据,但是返回的是本次读取到的实际字节数
//实际读取的字节数可能比length小
int readFrameData(unsigned int length);
//处理包头数据
void handleHead();
//处理图片的有效数据
void handlePhoto();
//处理关闭窗口/应用程序的操作
//主要是为了结束子线程
void dealClose();
private:
//初始化串口
void initSeialPort();
//发送图片(暂时没用到)
void sendPhoto();
private slots:
//串口选择下拉框
void on_serialSelect_currentIndexChanged(const QString &arg1);
//发送图片按钮(暂时没用到)
void on_sendButton_clicked();
//读取串口数据
void serialRead();
//发送图片按钮被按下的槽函数(暂时没用到)
void on_sendPhoto_button_clicked();
signals:
//启动子线程的信号
void startThread();
private:
Ui::MainWindow *ui;
//串口对象
QSerialPort serial;
//目标文件--图片文件
QFile dst;
unsigned int cnt_read;//总的已读取的字节数(只针对完整读取当前包)
unsigned int cnt_need;//还需要的字节数(只针对完整读取当前包)
unsigned int data_need;//每一个包的有效数据的总长度
unsigned int cnt;//串口接收到的所有有效数据的字节数(针对读取图片的整个过程)
QByteArray read_data;//总的已读取的数据(只针对完整读取当前包)
//缓冲区,当读取的有效数据累计满32*64的时候在进行写入文件操作,减少写文件的次数,以提高速度
QByteArray my_stream;
int photo_state;//读取图片的操作状态--对应BEGIN/READING/END
int serial_state;//读取串口的状态(读取包头/读取有效数据--对应READ_HDR/READ_DATA)
//为了以后扩展系统--一个协调器可能接收来自多个终端节点的数据
int node_type;//节点类型(判断当前数据包是哪一种类型的节点发过来的)
int node_id;//节点序号(同类节点有可能有多个)
unsigned int seqnb;//当前数据包的序号
MyThread *myT;//自定义对象--将要放入子线程
QThread *thread;//子线程--负责定时2ms,2ms一到就发送读取串口的信号
bool FAIL_FLAG;//读取的数据包是否发生丢失或者重复
unsigned int pkt_cnt;//读取到图片有效数据的包的个数--满32个就进行一次写入操作
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include <QApplication>
#include <QTime>
#include <QDateTime>
#include <QIODevice>
#include <QDir>
#include <QImage>
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
extern FILE * fopen(const char * path,const char * mode);
extern int fclose( FILE *fp );
extern size_t fread ( void *buffer, size_t size, size_t count, FILE *stream) ;
extern size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);
#ifdef __cplusplus
}
#endif /* __cplusplus */
//MainWindow的构造函数--也是主线程的开始函数
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
//记录读取状态相关变量的初始化
cnt_read = 0;
cnt_need = 0;
photo_state = BEGIN;//默认状态是开始读取图片(暂时没用到)
serial_state = READ_HDR;//默认状态是读取包头的状态
data_need = 0;
node_id = 0;
node_type = 0;
cnt = 0;
seqnb = 0;
FAIL_FLAG = false;//默认没有失败
pkt_cnt = 0;
qDebug() << "主线程号:" << QThread::currentThread();
//对于子线程的东西(将被移入子线程的自定义对象以及线程对象),最好定义为指针
myT = new MyThread;//将被子线程处理的自定义对象不能在主线程初始化的时候指定父对象
thread = new QThread(this);//初始化子线程线程
//连接主线程的启动线程信号和自定义对象(将被子线程处理)的mySerialRead槽函数(子线程槽函数)
//该对象(*myT)的所有成员函数都在子线程执行
connect(this, &MainWindow::startThread, myT, &MyThread::mySerialRead);
//将自定义对象移交给子线程,从此子线程控制他的成员函数
myT->moveToThread(thread);
//启动子线程,但是没有启动真正的子线程处理函数,
//只是让子线程对象开始监控移交给他的相关对象
thread->start();
//绑定/连接关闭应用程序窗口的信号和主线程的dealClose槽函数
connect(this, &MainWindow::destroyed, this, &MainWindow::dealClose);
//绘制界面
ui->setupUi(this);
//初始化串口--这里的初始化实际上只是探测当前系统可用的串口列表
initSeialPort();
}
//析构函数
MainWindow::~MainWindow()
{
//关闭串口
serial.close();
delete ui;
}
//处理串口选择下拉框被点击
void MainWindow::on_serialSelect_currentIndexChanged(const QString &arg1)
{
QSerialPortInfo info;
//获取可用串口列表
QList<QSerialPortInfo> infos = QSerialPortInfo::availablePorts();
//遍历链表
int i = 0;
foreach (info, infos) {
//如果在下拉框里选择的串口在系统可用串口链表里找到就跳出循环--表示能够操作该串口
if(info.portName() == arg1) break;
i++;
}
//实际意义的串口初始化
if(i != infos.size ()){//can find--没有遍历到可用串口链表尾部
ui->label->setText("[已开启]");
if(serial.isOpen())
serial.close();//先关闭
serial.setPort(info);//设置串口号--就是从下拉框选择的串口号
serial.open(QIODevice::ReadWrite); //读写打开
serial.setBaudRate(QSerialPort::Baud115200); //波特率
serial.setDataBits(QSerialPort::Data8); //数据位
serial.setParity(QSerialPort::NoParity); //无奇偶校验
serial.setStopBits(QSerialPort::OneStop); //停止位
serial.setFlowControl(QSerialPort::NoFlowControl); //无控制
emit startThread();//发送启动子线程的信号--实际意义的启动子线程处理函数
}
else
{
if(serial.isOpen())
serial.close();//如果没有找到可用串口--关闭串口
ui->label->setText("[出错]");
}
}
//发送按钮被按下的槽函数
void MainWindow::on_sendButton_clicked()
{
if(ui->lineEdit->text().isEmpty())//检查发送输入框是否为空
return;
serial.write(ui->lineEdit->text().toLatin1());//将输入框内容发送给串口
}
//发送图片按钮(暂时没用到)
void MainWindow::sendPhoto()
{
#if 0
FILE* src = NULL;
FILE* dst = NULL;
unsigned char tmp_cnt = 0;
char buf[MAX_BUF+1]={0};
src = fopen(SRC,"rb");
if(NULL == src)
{
qDebug()<<"src"<<" error!n";
}
dst = fopen(DST,"wb+");
if(NULL == dst)
{
qDebug()<<"dst"<<" error!n";
}
while((tmp_cnt = fread(&(buf[1]),1,MAX_BUF,src)) >= MAX_BUF)
{
fwrite(&(buf[1]),1,MAX_BUF,dst);
//write(fd,buf,MAX_BUF);
buf[0] = tmp_cnt+1;
qDebug()<<buf[0]<<endl;
serial.write(buf,buf[0]);
QTime reachTime = QTime::currentTime().addMSecs(100);
while(QTime::currentTime() < reachTime)
{
QCoreApplication::processEvents(QEventLoop::AllEvents,100);
}
}
fwrite(&(buf[1]),1,tmp_cnt,dst);
//write(fd,buf,tmp_cnt);
buf[0] = tmp_cnt+1;
serial.write(buf,buf[0]);
fclose(src);
fclose(dst);
#endif
}
//初始化串口--这里的初始化实际上只是探测当前系统可用的串口列表
void MainWindow::initSeialPort()
{
//connect(&serial,SIGNAL(readyRead()),this,SLOT(serialRead())); //连接槽
//连接子线程的mySignal信号(子线程2ms发送一次)和主线程的serialRead槽函数(实际读取串口的函数)
connect(myT,&MyThread::mySignal,this,&MainWindow::serialRead);
//获取可用串口列表
QList<QSerialPortInfo> infos = QSerialPortInfo::availablePorts();
if(infos.isEmpty())//系统无可用串口
{
ui->serialSelect->addItem("无效");//在串口选择下拉框显示“无效”
return;
}
ui->serialSelect->addItem("串口");//如果有可用串口则在串口选择下拉框显示“串口”
//将每个可用串口号作为一个条目添加到串口选择下拉框
foreach (QSerialPortInfo info, infos) {
ui->serialSelect->addItem(info.portName());
}
}
//发送图片按钮按下的槽函数(暂时没用到)
void MainWindow::on_sendPhoto_button_clicked()
{
//sendPhoto();
}
//将QByteArray类型的数据转换为int类型
int bytesToInt(QByteArray bytes) {
int addr = bytes[0] & 0x000000FF;
addr |= ((bytes[1] << 8) & 0x0000FF00);
addr |= ((bytes[2] << 16) & 0x00FF0000);
addr |= ((bytes[3] << 24) & 0xFF000000);
return addr;
}
//读取指定长度串口数据(实际不一定能读取指定的长度)
//实际读取到的字节数 小于等于 给定的长度
int MainWindow::readFrameData(unsigned int length)
{
QByteArray tmp_data;//存放本次读取到的临时数据
int cnt_tmp;//存放本次读取到的临时长度
cnt_need = length - cnt_read;//更新当前还需要读取的字节数
tmp_data = serial.read(cnt_need);//本次读取的有效数据
if(tmp_data.isEmpty())//如果读取空内容直接返回-1表示读取错误
return -1;
cnt_tmp = tmp_data.length();//获取本次读取到的字节数
cnt_read += cnt_tmp;//已经读取的总字节数(只针对读取一个指定长度的数据包)
read_data += tmp_data;//已经读取的数据(只针对读取一个指定长度的数据包)
return cnt_tmp;//返回本次读取的实际字节数
}
//处理包头
void MainWindow::handleHead()
{
static unsigned int seq_old = 0;//记录上一次读取到的数据包的序号
//能够执行这个函数说明已经读完了指定包头长度的数据(表示读完了包头),要进行第二部分指定长度的数据读取了(有效数据的读取)
//将记录读取状态的相关变量清零
cnt_read = 0;
cnt_need = 0;
//读完头部数据下一个状态应该是读取有效数据--切换状态
serial_state = READ_DATA;
//获取包头里的有用信息
node_type = bytesToInt(read_data.mid(0,1));//节点类型
node_id = bytesToInt(read_data.mid(1,1));//节点id
data_need = bytesToInt(read_data.mid(7,1));//有效数据的长度--很重要
seqnb = bytesToInt(read_data.mid(6,1))*256 + bytesToInt(read_data.mid(5,1));//该数据包的序号--也很重要
//如果该数据包序号和上一个数据包序号相等--读重复了
if(seqnb == seq_old)
{
FAIL_FLAG = true;//重复--读失败的标志置位--该数据包将不会写入图片文件
qDebug()<<"seqnb err..********************************";
}
else if(seqnb - seq_old > 1)//如果该数据包序号比上一个数据包序号大于等于2,表示中间丢了数据包
{
//虽然读取失败了,但是该数据包是需要写入图片文件的,所以失败标志复位--要写入该数据包到图片文件
FAIL_FLAG = false;
//计算丢失的数据包个数
int need_pkt = seqnb - seq_old -1;
QByteArray errData(64*need_pkt,0);//构造一个和丢失的所有数据包总和一样大、全0的数据包
//将上述构造的数据包加到缓冲区
my_stream += errData;
//将缓冲区所有数据写入图片文件
dst.write(my_stream);
//清空缓冲区
my_stream.clear();
//记录缓冲区是否满32*64的变量清零--表示重新计数(此时缓冲区已经没有数据了)
pkt_cnt = 0;
}
else {//既没有重复读取也没有丢失数据包
FAIL_FLAG = false;
}
//更新旧的数据包序号
seq_old = seqnb;
//操作头部数据
QString str_display;
QString str = read_data.toHex().data();//转换为16进制,再转为char*
str = str.toUpper();//转换为大写形式
str_display.clear();
for(int i = 0;i < str.length();i+= 2)
{
QString st = str.mid(i,2);//取出16进制的char*中的两个字符(就是一个完整的16进制数字)
str_display += st;//累加到str_display
str_display += " ";//相邻两个16进制数据之间添加一个空格,方便显示
}
//在接受文本编辑框接显示收到的包头数据
ui->textEdit->insertPlainText(str_display);
//清空读取到的数据(只针对读取一个指定长度的数据包)
read_data.clear();
}
void MainWindow::handlePhoto()
{
//能够执行这个函数说明已经读完了一个数据包的效数据,要进行下一个数据包的数据读取了(又要从包头开始读取)
//记录读取状态的变量清零--以便下一个指定长度的读取
cnt_read = 0;
cnt_need = 0;
serial_state = READ_HDR;//更新串口读取状态--立马要读取下一个数据包的包头了
//if(photo_state == END && strcmp("endrn",str_tmp) == 0)
//if(strcmp("end",str_tmp) == 0)
if(read_data.contains("end"))//如果读取到的有效数据包含end--表示读取到图片结束
{
dst.close();//关闭图片文件
//打印调试信息
qDebug()<<"end";
qDebug()<<cnt;
//清空相关缓冲区和--准备读取下一个数据包了
//(只针对读取一个指定长度的数据包)已读取的数据清空
read_data.clear();
//缓冲区清空
my_stream.clear();
//更新图片的读取状态(暂时没用到)
photo_state = BEGIN;
//图片的有效数据长度清零
data_need = 0;
//读取到的所有有效数据清零
cnt = 0;
return ;//直接返回--后面的没必要再执行了
}
//if(photo_state == BEGIN && strcmp("beginrn",str_tmp) == 0)
//if(strcmp("beginrn",str_tmp) == 0)
if(read_data.contains("begin"))//如果读取到的有效数据包含begin--表示准备开始读取图片
{
//将系统当前时间作为图片的文件名
QDateTime time = QDateTime::currentDateTime();//获取系统现在的时间
//设置显示格式,注意QFile的文件名不能有:(冒号)等特殊字符
QString str = time.toString("yyyy-MM-dd-hh-mm-ss");
str += ".jpg";
qDebug()<<str;//打印调试信息
dst.setFileName(str);//将时间作为文件名
//QDir::currentPath()
//打开文件
bool isOK = dst.open(QIODevice::WriteOnly|QIODevice::Append);
if(isOK == false)//打开失败
{
qDebug()<<"dst.open err";
this->close();
}
//清空相关缓冲区和--准备读取下一个数据包了
read_data.clear();
data_need = 0;
photo_state = READING;//更新图片读取状态(暂时没用到)
return ;//直接返回--后面的没必要再执行了
}
//if(photo_state == READING)//读取图片的实际有效数据
{
cnt += read_data.length();//累加图片的有效数据
//如果重复了--不会写入当前数据包到图片文件
if(FAIL_FLAG == true)
{
//清空已读取到的数据(但不清空缓冲区--实际不重复的有效数据没有满32*64)--准备读取下一个数据包的数据
read_data.clear();
data_need = 0;//有效数据长度清零
return;//直接返回
}
// //qDebug()<<"==========>"<<seqnb;
pkt_cnt++;//记录不重复的有效数据包的个数
my_stream += read_data;//不重复的有效数据包累加到缓冲区
//如果当前数据包的有效长度小于给定的有效数据包的长度的宏定义--表示是最后一个数据包
if(data_need < REAL_LEN)
{
photo_state = END;//更新图片读取状态(暂时没用到)
dst.write(my_stream);//将当前缓冲区的数据写入图片文件
my_stream.clear();//清空缓冲区
pkt_cnt = 0;//记录不重复有效数据包的个数清零
}
//还没有读取完毕,但是缓冲区已经满了32*64(这里的64是一个数据包里有效数据的最大长度--对应宏定义REAL_LEN)
if(pkt_cnt == 32)
{
pkt_cnt = 0;//记录不重复有效数据包的个数清零
dst.write(my_stream);//将当前缓冲区的数据写入图片文件
my_stream.clear();//清空缓冲区
}
//已读取的数据清空(只针对读取一个指定长度的数据包)
read_data.clear();
data_need = 0;//图片的有效数据长度清零
}
}
//处理关闭窗口/应用程序的操作
void MainWindow::dealClose()
{
qDebug()<<"dealClose";
if(thread->isRunning() == false)
{
return;
}
//2.如果调用的是子线程的函数(对象已被放入子线程,其成员函数均在子线程)
//需要在子线程退出的之前调用
myT->setFlag(true);
//3.退出子线程要显示的调用这两个函数,否则主线程退出但子线程还在运行
thread->quit();
//回收资源
thread->wait();
delete myT;
}
//读取串口数据--由于子线程2ms发送一次mySignal信号,
//所以在主线程这个槽函数会2ms执行一次
void MainWindow::serialRead()
{
int ret = 0;//记录每次实际读取的字节数
if(serial.bytesAvailable() >= 1)//有可读数据再去读
{
switch(serial_state)
{
case READ_HDR://读包头
ret = readFrameData(HDR_LEN);//目标是读取HDR_LEN个字节的数据
if(ret == -1)//读取错误
{
return;
}
if(HDR_LEN == cnt_read)//已读取到的字节数和目标长度相等
handleHead();//处理头部数据
break;
case READ_DATA://读有效数据
if(node_type == 1)//如果是图像节点的数据(不再判断节点--目前只有一个节点的数据)
{
ret = readFrameData(data_need);//读取有效长度(从包头获取)的数据
if(ret == -1)//读取错误
{
return;
}
if(data_need == cnt_read)//已读取到的字节数和目标长度相等
handlePhoto();//处理有效数据
}
break;
default:
break;
}
}
}
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
#include <QThread>
class MyThread : public QObject
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
void mySerialRead();//子线程处理函数--2ms发送一次信号给主线程--提醒他读取串口
void setFlag(bool flag);//更新isStop标志
signals:
void mySignal();//子线程给主线程发送的信号
private:
bool isStop;//控制子线程的处理函数是否结束
public slots:
};
#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
#include <QDebug>
MyThread::MyThread(QObject *parent) : QObject(parent)
{
isStop = false;//默认是false--不退出子线程处理函数
}
void MyThread::mySerialRead()
{
while(!isStop )//isStop是false--一直执行
{
QThread::msleep(2);//睡眠2ms
emit mySignal();//发送mySignal--通知主线程读取串口
}
}
void MyThread::setFlag(bool flag)
{
isStop = flag;
//5. 子线程中声明、初始化的对象在子线程中析构,
//利用deleteLater该函数可很好解决多线程释放对象
//serial->deleteLater();
qDebug() << "stop";
}
终端节点和协调器之间采用乒乓包的形式:
协调器一旦接收到终端节点的数据就反馈,终端节点接到协调器反馈以后再通过串口给ARM反馈,继续发送下一帧数据包
终端节点:
/**************************************************************************************************
Filename: SimonApp.c
Revised: $Date: 2009-03-18 15:56:27 -0700 (Wed, 18 Mar 2009) $
Revision: $Revision: 19453 $
Description: Generic Application (no Profile).
Copyright 2004-2009 Texas Instruments Incorporated. All rights reserved.
IMPORTANT: Your use of this Software is limited to those specific rights
granted under the terms of a software license agreement between the user
who downloaded the software, his/her employer (which must be your employer)
and Texas Instruments Incorporated (the "License"). You may not use this
Software unless you agree to abide by the terms of the License. The License
limits your use, and you acknowledge, that the Software may not be modified,
copied or distributed unless embedded on a Texas Instruments microcontroller
or used solely and exclusively in conjunction with a Texas Instruments radio
frequency transceiver, which is integrated into your product. Other than for
the foregoing purpose, you may not use, reproduce, copy, prepare derivative
works of, modify, distribute, perform, display or sell this Software and/or
its documentation for any purpose.
YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
PROVIDED 揂S IS?WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
Should you have any questions regarding your right to use this Software,
contact Texas Instruments Incorporated at www.TI.com.
**************************************************************************************************/
/*********************************************************************
This application isn't intended to do anything useful, it is
intended to be a simple example of an application's structure.
This application sends "Hello World" to another "Generic"
application every 15 seconds. The application will also
receive "Hello World" packets.
The "Hello World" messages are sent/received as MSG type message.
This applications doesn't have a profile, so it handles everything
directly - itself.
Key control:
SW1:
SW2: initiates end device binding
SW3:
SW4: initiates a match description request
*********************************************************************/
/*********************************************************************
* INCLUDES
*/
#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "ZDObject.h"
#include "ZDProfile.h"
#include "SimonApp.h"
#include "DebugTrace.h"
#if !defined( WIN32 )
#include "OnBoard.h"
#endif
/* HAL */
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_key.h"
#include "hal_uart.h"
#include"74LS164_8LED.h"
#include "SD_Key.h"
/*********************************************************************
* MACROS
*/
/*********************************************************************
* CONSTANTS
*/
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* GLOBAL VARIABLES
*/
// This list should be filled with Application specific Cluster IDs.
const cId_t SimonApp_ClusterList[SimonApp_MAX_CLUSTERS] =
{
SimonApp_CLUSTERID
};
const SimpleDescriptionFormat_t SimonApp_SimpleDesc =
{
SimonApp_ENDPOINT, // int Endpoint;
SimonApp_PROFID, // uint16 AppProfId[2];
SimonApp_DEVICEID, // uint16 AppDeviceId[2];
SimonApp_DEVICE_VERSION, // int AppDevVer:4;
SimonApp_FLAGS, // int AppFlags:4;
SimonApp_MAX_CLUSTERS, // byte AppNumInClusters;
(cId_t *)SimonApp_ClusterList, // byte *pAppInClusterList;
SimonApp_MAX_CLUSTERS, // byte AppNumInClusters;
(cId_t *)SimonApp_ClusterList // byte *pAppInClusterList;
};
// This is the Endpoint/Interface description. It is defined here, but
// filled-in in SimonApp_Init(). Another way to go would be to fill
// in the structure here and make it a "const" (in code space). The
// way it's defined in this sample app it is define in RAM.
endPointDesc_t SimonApp_epDesc;
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
byte SimonApp_TaskID; // Task ID for internal task/event processing
// This variable will be received when
// SimonApp_Init() is called.
devStates_t SimonApp_NwkState;
byte SimonApp_TransID; // This is the unique message ID (counter)
afAddrType_t SimonApp_DstAddr;
uint16 myAddr = 0;
uint16 mySeq = 0;
/*added by Simon*/
/*added by Simon*/
#define BUF_MAX 72//payload for zstack max 75
#define MY_PORT_NUM 0
uint8 gUartBuf[BUF_MAX];
/*************************************************************************/
/*| 1 | 1 | 2 | 1 | 2 | 1 | 64 |*/
/*-----------------------------------------------------------------------*/
/*| type | id | shortAddr| endpoint | sequence | len | Data |*/
/*************************************************************************/
static void rxCB(uint8 port,uint8 event);
#define MY_ENDPOINT 11
/*********************************************************************
* LOCAL FUNCTIONS
*/
void SimonApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg );
void SimonApp_HandleKeys( byte shift, byte keys );
void SimonApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );
void SimonApp_SendTheMessage( void );
/*********************************************************************
* NETWORK LAYER CALLBACKS
*/
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/*********************************************************************
* @fn SimonApp_Init
*
* @brief Initialization function for the Generic App Task.
* This is called during initialization and should contain
* any application specific initialization (ie. hardware
* initialization/setup, table initialization, power up
* notificaiton ... ).
*
* @param task_id - the ID assigned by OSAL. This ID should be
* used to send messages and set timers.
*
* @return none
*/
void SimonApp_Init( byte task_id )
{
/*added by Simon*/
halUARTCfg_t uartConfig;
SimonApp_TaskID = task_id;
SimonApp_NwkState = DEV_INIT;
SimonApp_TransID = 0;
// Device hardware initialization can be added here or in main() (Zmain.c).
// If the hardware is application specific - add it here.
// If the hardware is other parts of the device add it in main().
SimonApp_DstAddr.addrMode = (afAddrMode_t)AddrNotPresent;
SimonApp_DstAddr.endPoint = 0;
SimonApp_DstAddr.addr.shortAddr = 0;
// Fill out the endpoint description.
SimonApp_epDesc.endPoint = MY_ENDPOINT;//SimonApp_ENDPOINT;
SimonApp_epDesc.task_id = &SimonApp_TaskID;
SimonApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&SimonApp_SimpleDesc;
SimonApp_epDesc.latencyReq = noLatencyReqs;
// Register the endpoint description with the AF
afRegister( &SimonApp_epDesc );
// Register for all key events - This app will handle all key events
RegisterForKeys( SimonApp_TaskID );
/*added by Simon Initialize the uart*/
uartConfig.configured = TRUE;
uartConfig.baudRate = HAL_UART_BR_115200;
uartConfig.flowControl = FALSE;
uartConfig.flowControlThreshold = 256; // 2x30 don't care - see uart driver.
uartConfig.rx.maxBufSize = 256; // 2x30 don't care - see uart driver.
uartConfig.tx.maxBufSize = 256; // 2x30 don't care - see uart driver.
uartConfig.idleTimeout = 6; // 2x30 don't care - see uart driver.
uartConfig.intEnable = TRUE; // 2x30 don't care - see uart driver.
uartConfig.callBackFunc = rxCB;
HalUARTOpen(MY_PORT_NUM,&uartConfig);
mySeq = 0;//初始化数据包序号
// Update the display
#if defined ( LCD_SUPPORTED )
HalLcdWriteString( "SimonApp", HAL_LCD_LINE_1 );
#endif
ZDO_RegisterForZDOMsg( SimonApp_TaskID, End_Device_Bind_rsp );
ZDO_RegisterForZDOMsg( SimonApp_TaskID, Match_Desc_rsp );
}
/*********************************************************************
* @fn SimonApp_ProcessEvent
*
* @brief Generic Application Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The OSAL assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return none
*/
UINT16 SimonApp_ProcessEvent( byte task_id, UINT16 events )
{
afIncomingMSGPacket_t *MSGpkt;
afDataConfirm_t *afDataConfirm;
// Data Confirmation message fields
byte sentEP;
ZStatus_t sentStatus;
byte sentTransID; // This should match the value sent
(void)task_id; // Intentionally unreferenced parameter
if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SimonApp_TaskID );
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
case ZDO_CB_MSG:
SimonApp_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt );
break;
case KEY_CHANGE:
SimonApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
break;
case AF_DATA_CONFIRM_CMD:
// This message is received as a confirmation of a data packet sent.
// The status is of ZStatus_t type [defined in ZComDef.h]
// The message fields are defined in AF.h
afDataConfirm = (afDataConfirm_t *)MSGpkt;
sentEP = afDataConfirm->endpoint;
sentStatus = afDataConfirm->hdr.status;
sentTransID = afDataConfirm->transID;
(void)sentEP;
(void)sentTransID;
// Action taken when confirmation is received.
if ( sentStatus != ZSuccess )
{
// The data wasn't delivered -- Do something
}
break;
case AF_INCOMING_MSG_CMD:
SimonApp_MessageMSGCB( MSGpkt );
break;
case ZDO_STATE_CHANGE:
SimonApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
#if 0
if ( (SimonApp_NwkState == DEV_ZB_COORD)
|| (SimonApp_NwkState == DEV_ROUTER)
|| (SimonApp_NwkState == DEV_END_DEVICE) )
{
// Start sending "the" message in a regular interval.
osal_start_timerEx( SimonApp_TaskID,
SimonApp_SEND_MSG_EVT,
SimonApp_SEND_MSG_TIMEOUT );
}
#endif
/*网络状态改变的指示操作*/
if (SimonApp_NwkState == DEV_ZB_COORD)
{
LS164_BYTE(11);
osal_set_event( SimonApp_TaskID, SimonApp_SEND_MSG_EVT );
}
if (SimonApp_NwkState == DEV_ROUTER)
{
LS164_BYTE(12);
}
if (SimonApp_NwkState == DEV_END_DEVICE)
{
LS164_BYTE(13);
}
break;
default:
break;
}
// Release the memory
osal_msg_deallocate( (uint8 *)MSGpkt );
// Next
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SimonApp_TaskID );
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
// Send a message out - This event is generated by a timer
// (setup in SimonApp_Init()).
if ( events & SimonApp_SEND_MSG_EVT )
{
#if 0
// Send "the" message
SimonApp_SendTheMessage();
// Setup to send message again
osal_start_timerEx( SimonApp_TaskID,
SimonApp_SEND_MSG_EVT,
SimonApp_SEND_MSG_TIMEOUT );
#endif
P0DIR |=0X02;
P0_1=0;
myAddr = NLME_GetShortAddr();
// return unprocessed events
return (events ^ SimonApp_SEND_MSG_EVT);
}
if ( events & SimonApp_MY_EVT )
{
if(0==P1_1)
{//按钮3按下,给协调器的7号端点的0x0001号员工发送数据3
char theMessageData[] ={3};
SimonApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
SimonApp_DstAddr.addr.shortAddr = 0x0000;
// Take the first endpoint, Can be changed to search through endpoints
SimonApp_DstAddr.endPoint = 7;
AF_DataRequest( &SimonApp_DstAddr, &SimonApp_epDesc,
0x0001,
1,//(byte)osal_strlen( theMessageData ) + 1,
(byte *)&theMessageData,
&SimonApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
}
if(0==P2_0)
{//按钮4按下,协调器的7号端点的0x0002号员工发送数据4
char theMessageData[] ={4};
SimonApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
SimonApp_DstAddr.addr.shortAddr = 0x0000;
// Take the first endpoint, Can be changed to search through endpoints
SimonApp_DstAddr.endPoint = 7;
AF_DataRequest( &SimonApp_DstAddr, &SimonApp_epDesc,
0x0002,
1,//(byte)osal_strlen( theMessageData ) + 1,
(byte *)&theMessageData,
&SimonApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
}
if(0==P0_5)
{//按钮5按下,协调器的6号端点的0x0001号员工发送数据5
char theMessageData[] ={5};
SimonApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
SimonApp_DstAddr.addr.shortAddr = 0x0000;
// Take the first endpoint, Can be changed to search through endpoints
SimonApp_DstAddr.endPoint = 6;
AF_DataRequest( &SimonApp_DstAddr, &SimonApp_epDesc,
0x0001,
1,//(byte)osal_strlen( theMessageData ) + 1,
(byte *)&theMessageData,
&SimonApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
}
return (events ^ SimonApp_MY_EVT);
}
// Discard unknown events
return 0;
}
/*********************************************************************
* Event Generation Functions
*/
/*********************************************************************
* @fn SimonApp_ProcessZDOMsgs()
*
* @brief Process response messages
*
* @param none
*
* @return none
*/
void SimonApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg )
{
switch ( inMsg->clusterID )
{
case End_Device_Bind_rsp:
if ( ZDO_ParseBindRsp( inMsg ) == ZSuccess )
{
// Light LED
HalLedSet( HAL_LED_4, HAL_LED_MODE_ON );
}
#if defined(BLINK_LEDS)
else
{
// Flash LED to show failure
HalLedSet ( HAL_LED_4, HAL_LED_MODE_FLASH );
}
#endif
break;
case Match_Desc_rsp:
{
ZDO_ActiveEndpointRsp_t *pRsp = ZDO_ParseEPListRsp( inMsg );
if ( pRsp )
{
if ( pRsp->status == ZSuccess && pRsp->cnt )
{
SimonApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
SimonApp_DstAddr.addr.shortAddr = pRsp->nwkAddr;
// Take the first endpoint, Can be changed to search through endpoints
SimonApp_DstAddr.endPoint = pRsp->epList[0];
// Light LED
HalLedSet( HAL_LED_4, HAL_LED_MODE_ON );
}
osal_mem_free( pRsp );
}
}
break;
}
}
/*********************************************************************
* @fn SimonApp_HandleKeys
*
* @brief Handles all key events for this device.
*
* @param shift - true if in shift/alt.
* @param keys - bit field for key events. Valid entries:
* HAL_KEY_SW_4
* HAL_KEY_SW_3
* HAL_KEY_SW_2
* HAL_KEY_SW_1
*
* @return none
*/
void SimonApp_HandleKeys( byte shift, byte keys )
{
zAddrType_t dstAddr;
// Shift is used to make each button/switch dual purpose.
if ( shift )
{
if ( keys & HAL_KEY_SW_1 )
{
}
if ( keys & HAL_KEY_SW_2 )
{
}
if ( keys & HAL_KEY_SW_3 )
{
}
if ( keys & HAL_KEY_SW_4 )
{
}
}
else
{
if ( keys & HAL_KEY_SW_1 )
{
}
if ( keys & HAL_KEY_SW_2 )
{
HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
// Initiate an End Device Bind Request for the mandatory endpoint
dstAddr.addrMode = Addr16Bit;
dstAddr.addr.shortAddr = 0x0000; // Coordinator
ZDP_EndDeviceBindReq( &dstAddr, NLME_GetShortAddr(),
SimonApp_epDesc.endPoint,
SimonApp_PROFID,
SimonApp_MAX_CLUSTERS, (cId_t *)SimonApp_ClusterList,
SimonApp_MAX_CLUSTERS, (cId_t *)SimonApp_ClusterList,
FALSE );
}
if ( keys & HAL_KEY_SW_3 )
{
}
if ( keys & HAL_KEY_SW_4 )
{
HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
// Initiate a Match Description Request (Service Discovery)
dstAddr.addrMode = AddrBroadcast;
dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR;
ZDP_MatchDescReq( &dstAddr, NWK_BROADCAST_SHORTADDR,
SimonApp_PROFID,
SimonApp_MAX_CLUSTERS, (cId_t *)SimonApp_ClusterList,
SimonApp_MAX_CLUSTERS, (cId_t *)SimonApp_ClusterList,
FALSE );
}
}
}
/*********************************************************************
* LOCAL FUNCTIONS
*/
/*********************************************************************
* @fn SimonApp_MessageMSGCB
*
* @brief Data message processor callback. This function processes
* any incoming data - probably from other devices. So, based
* on cluster ID, perform the intended action.
*
* @param none
*
* @return none
*/
void SimonApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )//在接收方成功接收以后会发送数据到该模块
{
//static uint16 seqnb = 0;//留待以后扩展
//seqnb++;
//uint8 msg[2]={0};
//msg[0] = seqnb %256;
//msg[1] = seqnb /256;
switch ( pkt->clusterId )
{
case CLUSTER_PHOTO_NODE://实际簇---房间里到底是谁
if(1 == pkt->cmd.Data[0])//接收方反馈1作为接收成功的应答
{
HalUARTWrite(MY_PORT_NUM,"OKrn",4);//向串口/上位机发送成功发送的反馈信息,不需要在堆栈寻址或者说发送的是常量
// //HalUARTWrite(MY_PORT_NUM,(uint8 *)(&seqnb),2);//这样很慢,估计和协议栈的内存布局有关,需要再寻址
}
//HalUARTWrite(MY_PORT_NUM,pkt->cmd.Data,pkt->cmd.DataLength);//这样很慢,估计和协议栈的内存布局有关,需要再寻址
//HalUARTWrite(MY_PORT_NUM,"OKrn",4);
//HalUARTWrite(MY_PORT_NUM,msg,2);
break;
}
}
/*********************************************************************
* @fn SimonApp_SendTheMessage
*
* @brief Send "the" message.
*
* @param none
*
* @return none
*/
void SimonApp_SendTheMessage( void )
{
char theMessageData[] = "Hello World";
if ( AF_DataRequest( &SimonApp_DstAddr, &SimonApp_epDesc,
SimonApp_CLUSTERID,
(byte)osal_strlen( theMessageData ) + 1,
(byte *)&theMessageData,
&SimonApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
{
// Successfully requested to be sent.
}
else
{
// Error occurred in request to send.
}
}
/*********************************************************************
*********************************************************************/
/*added by Simon*/
/*当串口接收到上位机的数据以后,打包-->发送给协调器*/
static void rxCB(uint8 port,uint8 event)
{
static uint8 tmp_len = 0;
//osal_memset(gUartBuf,0,BUF_MAX);
//在协议栈的回调函数里必须加上该条件判断才能正常使用回调功能
//回调函数默认是利用DMA的轮询方式工作
if ((event & (HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT)) &&!tmp_len)
{
if(!tmp_len)//tmp_len必须是0
{
osal_memset(gUartBuf,0,BUF_MAX);//清空缓冲区
tmp_len=HalUARTRead(MY_PORT_NUM,gUartBuf+5, BUF_MAX);//读取串口内容,此时的长度tmp_len为有效数据长度
/*开头的八个字节是节点的相关信息*/
gUartBuf[0] = TYPE_PHOTO;//节点类型
gUartBuf[1] = MY_ID;//同类节点中的节点序号
/*2530是低地址对应低字节*/
/*在网络数据包里尽量吧低字节放在低地址(数据包的前面)*/
/*该数据包在已发送序列中的序号*/
// mySeq++;
// //HalUARTWrite(MY_PORT_NUM,(uint8 *)&mySeq,2);
// gUartBuf[3] = (mySeq>>8);
// gUartBuf[4] = (mySeq%256);
//
/*该节点的网络短地址*/
myAddr = NLME_GetShortAddr();
gUartBuf[3] = (myAddr>>8);
gUartBuf[2] = (myAddr%256);
/*该节点用哪个端点给协调器发送数据*/
gUartBuf[4] = MY_ENDPOINT;
//gUartBuf[7] = 0;//保留未使用-->填充为0
//HalUARTWrite(MY_PORT_NUM,gUartBuf,tmp_len+3);
}
if(tmp_len>2 )//该参数有待修改
{
// HalUARTWrite(MY_PORT_NUM,(uint8*)&tmp_len,1);
//HalUARTWrite(MY_PORT_NUM,gUartBuf,tmp_len+3);
tmp_len += 5;//长度修正为实际数据包大小
/*填充目标地址*/
SimonApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;//单播模式
SimonApp_DstAddr.addr.shortAddr = 0x0000;//目标是协调器
// Take the first endpoint, Can be changed to search through endpoints
SimonApp_DstAddr.endPoint = MY_ENDPOINT02;//发送给协调器的6号端点
AF_DataRequest( &SimonApp_DstAddr, &SimonApp_epDesc,//端点描述符用默认填充的就好
CLUSTER_PHOTO_NODE,//6号端点里面的CLUSTER_PHOTO_NODE员工
tmp_len,//实际长度
(byte *)&gUartBuf,//打包好的数据
&SimonApp_TransID,//协议栈自动维护的数据包序号
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );//后两个参数默认不修改
}
tmp_len=0; //清空长度
}
}
协调器
/**************************************************************************************************
Filename: SimonApp.c
Revised: $Date: 2009-03-18 15:56:27 -0700 (Wed, 18 Mar 2009) $
Revision: $Revision: 19453 $
Description: Generic Application (no Profile).
Copyright 2004-2009 Texas Instruments Incorporated. All rights reserved.
IMPORTANT: Your use of this Software is limited to those specific rights
granted under the terms of a software license agreement between the user
who downloaded the software, his/her employer (which must be your employer)
and Texas Instruments Incorporated (the "License"). You may not use this
Software unless you agree to abide by the terms of the License. The License
limits your use, and you acknowledge, that the Software may not be modified,
copied or distributed unless embedded on a Texas Instruments microcontroller
or used solely and exclusively in conjunction with a Texas Instruments radio
frequency transceiver, which is integrated into your product. Other than for
the foregoing purpose, you may not use, reproduce, copy, prepare derivative
works of, modify, distribute, perform, display or sell this Software and/or
its documentation for any purpose.
YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
PROVIDED 揂S IS?WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
Should you have any questions regarding your right to use this Software,
contact Texas Instruments Incorporated at www.TI.com.
**************************************************************************************************/
/*********************************************************************
This application isn't intended to do anything useful, it is
intended to be a simple example of an application's structure.
This application sends "Hello World" to another "Generic"
application every 15 seconds. The application will also
receive "Hello World" packets.
The "Hello World" messages are sent/received as MSG type message.
This applications doesn't have a profile, so it handles everything
directly - itself.
Key control:
SW1:
SW2: initiates end device binding
SW3:
SW4: initiates a match description request
*********************************************************************/
/*********************************************************************
* INCLUDES
*/
#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "ZDObject.h"
#include "ZDProfile.h"
#include "SimonApp.h"
#include "DebugTrace.h"
#if !defined( WIN32 )
#include "OnBoard.h"
#endif
/* HAL */
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_key.h"
#include "hal_uart.h"
#include"74LS164_8LED.h"
#include "SD_Key.h"
//#include "UART.h"
/*********************************************************************
* MACROS
*/
//LCD_SUPPORTED=DEBUG
/*********************************************************************
* CONSTANTS
*/
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* GLOBAL VARIABLES
*/
// This list should be filled with Application specific Cluster IDs.
const cId_t SimonApp_ClusterList[SimonApp_MAX_CLUSTERS] =
{
SimonApp_CLUSTERID
};
const SimpleDescriptionFormat_t SimonApp_SimpleDesc =
{
SimonApp_ENDPOINT, // int Endpoint;
SimonApp_PROFID, // uint16 AppProfId[2];
SimonApp_DEVICEID, // uint16 AppDeviceId[2];
SimonApp_DEVICE_VERSION, // int AppDevVer:4;
SimonApp_FLAGS, // int AppFlags:4;
SimonApp_MAX_CLUSTERS, // byte AppNumInClusters;
(cId_t *)SimonApp_ClusterList, // byte *pAppInClusterList;
SimonApp_MAX_CLUSTERS, // byte AppNumInClusters;
(cId_t *)SimonApp_ClusterList // byte *pAppInClusterList;
};
// This is the Endpoint/Interface description. It is defined here, but
// filled-in in SimonApp_Init(). Another way to go would be to fill
// in the structure here and make it a "const" (in code space). The
// way it's defined in this sample app it is define in RAM.
endPointDesc_t SimonApp_epDesc;
endPointDesc_t SimonApp_epDesc1;
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
byte SimonApp_TaskID; // Task ID for internal task/event processing
// This variable will be received when
// SimonApp_Init() is called.
devStates_t SimonApp_NwkState;
byte SimonApp_TransID; // This is the unique message ID (counter)
afAddrType_t SimonApp_DstAddr;
/*********************************************************************
* LOCAL FUNCTIONS
*/
void SimonApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg );
void SimonApp_HandleKeys( byte shift, byte keys );
void SimonApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );
void SimonApp_SendTheMessage( void );
/*added by Simon*/
#define TINY_ID_MAX 16
#define PHOTO_ID_MAX 1
typedef struct _AddrInfo
{
uint16 shortAddr;
byte endPoint;
uint8 exist;
uint16 seqnb;
}AddrInfo_t;
AddrInfo_t *TinyNode_AddrArr;
AddrInfo_t *PothoNode_AddrArr;
#define BUF_MAX 72//payload for zstack max 75
#define MY_PORT_NUM 0
uint8 gUartBuf[10];
/*************************************************************************/
/*| 1 | 1 | 2 | 2 | 1 | 1 | 64 |*/
/*-----------------------------------------------------------------------*/
/*| type | id | sequence | shortAddr| endpoint | 0 | Data |*/
/*************************************************************************/
static void rxCB(uint8 port,uint8 event);
static void ResponsePhotoNode(void);
afAddrType_t gResponseAddr;
#define TYPE_PHOTO 0x01
#define HDR_LENGTH 8
static uint8 gPhotoID = 0;
/*********************************************************************
* NETWORK LAYER CALLBACKS
*/
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/*********************************************************************
* @fn SimonApp_Init
*
* @brief Initialization function for the Generic App Task.
* This is called during initialization and should contain
* any application specific initialization (ie. hardware
* initialization/setup, table initialization, power up
* notificaiton ... ).
*
* @param task_id - the ID assigned by OSAL. This ID should be
* used to send messages and set timers.
*
* @return none
*/
void SimonApp_Init( byte task_id )
{
/*added by Simon*/
halUARTCfg_t uartConfig;//串口配置变量
SimonApp_TaskID = task_id;
SimonApp_NwkState = DEV_INIT;
SimonApp_TransID = 0;
// Device hardware initialization can be added here or in main() (Zmain.c).
// If the hardware is application specific - add it here.
// If the hardware is other parts of the device add it in main().
SimonApp_DstAddr.addrMode = (afAddrMode_t)AddrNotPresent;
SimonApp_DstAddr.endPoint = 0;
SimonApp_DstAddr.addr.shortAddr = 0;
// Fill out the endpoint description.
SimonApp_epDesc.endPoint = MY_ENDPOINT01;//SimonApp_ENDPOINT;
SimonApp_epDesc.task_id = &SimonApp_TaskID;
SimonApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&SimonApp_SimpleDesc;
SimonApp_epDesc.latencyReq = noLatencyReqs;
// Register the endpoint description with the AF
afRegister( &SimonApp_epDesc );
/*=========================================================================*/
// Fill out the endpoint description.
SimonApp_epDesc1.endPoint = MY_ENDPOINT02;//SimonApp_ENDPOINT;
SimonApp_epDesc1.task_id = &SimonApp_TaskID;
SimonApp_epDesc1.simpleDesc
= (SimpleDescriptionFormat_t *)&SimonApp_SimpleDesc;
SimonApp_epDesc1.latencyReq = noLatencyReqs;
// Register the endpoint description with the AF
afRegister( &SimonApp_epDesc1 );
// Register for all key events - This app will handle all key events
RegisterForKeys( SimonApp_TaskID );
/*added by Simon Initialize the uart*/
uartConfig.configured = TRUE;
uartConfig.baudRate = HAL_UART_BR_115200;
uartConfig.flowControl = FALSE;
uartConfig.flowControlThreshold = 256; // 2x30 don't care - see uart driver.
uartConfig.rx.maxBufSize = 256; // 2x30 don't care - see uart driver.
uartConfig.tx.maxBufSize = 256; // 2x30 don't care - see uart driver.
uartConfig.idleTimeout = 6; // 2x30 don't care - see uart driver.
uartConfig.intEnable = TRUE; // 2x30 don't care - see uart driver.
uartConfig.callBackFunc = rxCB;
HalUARTOpen(MY_PORT_NUM,&uartConfig);//打开串口--默认情况下,在这里还不能正常使用串口--具体原因有待抽时间分析
TinyNode_AddrArr = (AddrInfo_t*)osal_mem_alloc(sizeof(AddrInfo_t)*TINY_ID_MAX);//给小节点(温湿度)存储地址信息的数组
PothoNode_AddrArr = (AddrInfo_t*)osal_mem_alloc(sizeof(AddrInfo_t)*PHOTO_ID_MAX);//给传图像的节点分配存储地址的信息
/*清空动态申请的内存空间*/
osal_memset(TinyNode_AddrArr,0,sizeof(AddrInfo_t)*TINY_ID_MAX);
osal_memset(PothoNode_AddrArr,0,sizeof(AddrInfo_t)*PHOTO_ID_MAX);
// Update the display
#if defined ( LCD_SUPPORTED )
HalLcdWriteString( "SimonApp", HAL_LCD_LINE_1 );
#endif
ZDO_RegisterForZDOMsg( SimonApp_TaskID, End_Device_Bind_rsp );
ZDO_RegisterForZDOMsg( SimonApp_TaskID, Match_Desc_rsp );
}
/*********************************************************************
* @fn SimonApp_ProcessEvent
*
* @brief Generic Application Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The OSAL assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return none
*/
UINT16 SimonApp_ProcessEvent( byte task_id, UINT16 events )
{
afIncomingMSGPacket_t *MSGpkt;
afDataConfirm_t *afDataConfirm;
// Data Confirmation message fields
byte sentEP;
ZStatus_t sentStatus;
byte sentTransID; // This should match the value sent
(void)task_id; // Intentionally unreferenced parameter
if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SimonApp_TaskID );
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
case ZDO_CB_MSG:
SimonApp_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt );
break;
case KEY_CHANGE:
SimonApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
break;
case AF_DATA_CONFIRM_CMD:
// This message is received as a confirmation of a data packet sent.
// The status is of ZStatus_t type [defined in ZComDef.h]
// The message fields are defined in AF.h
afDataConfirm = (afDataConfirm_t *)MSGpkt;
sentEP = afDataConfirm->endpoint;
sentStatus = afDataConfirm->hdr.status;
sentTransID = afDataConfirm->transID;
(void)sentEP;
(void)sentTransID;
// Action taken when confirmation is received.
if ( sentStatus != ZSuccess )
{
// The data wasn't delivered -- Do something
}
break;
case AF_INCOMING_MSG_CMD:
SimonApp_MessageMSGCB( MSGpkt );
break;
case ZDO_STATE_CHANGE:
SimonApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
#if 0
if ( (SimonApp_NwkState == DEV_ZB_COORD)
|| (SimonApp_NwkState == DEV_ROUTER)
|| (SimonApp_NwkState == DEV_END_DEVICE) )
{
// Start sending "the" message in a regular interval.
osal_start_timerEx( SimonApp_TaskID,
SimonApp_SEND_MSG_EVT,
SimonApp_SEND_MSG_TIMEOUT );
}
#endif
if (SimonApp_NwkState == DEV_ZB_COORD)//变为协调器,数码管显示C
{
LS164_BYTE(11);
osal_set_event( SimonApp_TaskID, SimonApp_SEND_MSG_EVT );//设置SimonApp_SEND_MSG_EVT以便执行SimonApp_SEND_MSG_EVT的处理函数
}
if (SimonApp_NwkState == DEV_ROUTER)//变为路由器,数码管显示R
{
LS164_BYTE(12);
}
if (SimonApp_NwkState == DEV_END_DEVICE)//变为终端节点,数码管显示E
{
LS164_BYTE(13);
}
break;
default:
break;
}
// Release the memory
osal_msg_deallocate( (uint8 *)MSGpkt );
// Next
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SimonApp_TaskID );
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
// Send a message out - This event is generated by a timer
// (setup in SimonApp_Init()).
if ( events & SimonApp_SEND_MSG_EVT )
{
#if 0
// Send "the" message
SimonApp_SendTheMessage();
// Setup to send message again
osal_start_timerEx( SimonApp_TaskID,
SimonApp_SEND_MSG_EVT,
SimonApp_SEND_MSG_TIMEOUT );
#endif
/*在变为协调器的同时点亮LED*/
P0DIR |=0X02;
P0_1=0;
// return unprocessed events
return (events ^ SimonApp_SEND_MSG_EVT);
}
if ( events & SimonApp_MY_EVT )
{
if(0==P1_1)
{//按钮3按下
LS164_BYTE(3);//显示3
}
if(0==P2_0)
{//按钮4按下
LS164_BYTE(4);
}
if(0==P0_5)
{//按钮5按下
LS164_BYTE(5);
}
return (events ^ SimonApp_MY_EVT);
}
/*在收到终端节点的数据以后要发送反馈信息给相应的终端节点*/
if ( events & SimonApp_RESPONSE_PHOTO_EVT )
{
ResponsePhotoNode();
return (events ^ SimonApp_RESPONSE_PHOTO_EVT);
}
// Discard unknown events
return 0;
}
/*********************************************************************
* Event Generation Functions
*/
/*********************************************************************
* @fn SimonApp_ProcessZDOMsgs()
*
* @brief Process response messages
*
* @param none
*
* @return none
*/
void SimonApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg )
{
switch ( inMsg->clusterID )
{
case End_Device_Bind_rsp:
if ( ZDO_ParseBindRsp( inMsg ) == ZSuccess )
{
// Light LED
HalLedSet( HAL_LED_4, HAL_LED_MODE_ON );
}
#if defined(BLINK_LEDS)
else
{
// Flash LED to show failure
HalLedSet ( HAL_LED_4, HAL_LED_MODE_FLASH );
}
#endif
break;
case Match_Desc_rsp:
{
ZDO_ActiveEndpointRsp_t *pRsp = ZDO_ParseEPListRsp( inMsg );
if ( pRsp )
{
if ( pRsp->status == ZSuccess && pRsp->cnt )
{
SimonApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
SimonApp_DstAddr.addr.shortAddr = pRsp->nwkAddr;
// Take the first endpoint, Can be changed to search through endpoints
SimonApp_DstAddr.endPoint = pRsp->epList[0];
// Light LED
HalLedSet( HAL_LED_4, HAL_LED_MODE_ON );
}
osal_mem_free( pRsp );
}
}
break;
}
}
/*********************************************************************
* @fn SimonApp_HandleKeys
*
* @brief Handles all key events for this device.
*
* @param shift - true if in shift/alt.
* @param keys - bit field for key events. Valid entries:
* HAL_KEY_SW_4
* HAL_KEY_SW_3
* HAL_KEY_SW_2
* HAL_KEY_SW_1
*
* @return none
*/
void SimonApp_HandleKeys( byte shift, byte keys )
{
zAddrType_t dstAddr;
// Shift is used to make each button/switch dual purpose.
if ( shift )
{
if ( keys & HAL_KEY_SW_1 )
{
}
if ( keys & HAL_KEY_SW_2 )
{
}
if ( keys & HAL_KEY_SW_3 )
{
}
if ( keys & HAL_KEY_SW_4 )
{
}
}
else
{
if ( keys & HAL_KEY_SW_1 )
{
}
if ( keys & HAL_KEY_SW_2 )
{
HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
// Initiate an End Device Bind Request for the mandatory endpoint
dstAddr.addrMode = Addr16Bit;
dstAddr.addr.shortAddr = 0x0000; // Coordinator
ZDP_EndDeviceBindReq( &dstAddr, NLME_GetShortAddr(),
SimonApp_epDesc.endPoint,
SimonApp_PROFID,
SimonApp_MAX_CLUSTERS, (cId_t *)SimonApp_ClusterList,
SimonApp_MAX_CLUSTERS, (cId_t *)SimonApp_ClusterList,
FALSE );
}
if ( keys & HAL_KEY_SW_3 )
{
}
if ( keys & HAL_KEY_SW_4 )
{
HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
// Initiate a Match Description Request (Service Discovery)
dstAddr.addrMode = AddrBroadcast;
dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR;
ZDP_MatchDescReq( &dstAddr, NWK_BROADCAST_SHORTADDR,
SimonApp_PROFID,
SimonApp_MAX_CLUSTERS, (cId_t *)SimonApp_ClusterList,
SimonApp_MAX_CLUSTERS, (cId_t *)SimonApp_ClusterList,
FALSE );
}
}
}
/*********************************************************************
* LOCAL FUNCTIONS
*/
/*********************************************************************
* @fn SimonApp_MessageMSGCB
*
* @brief Data message processor callback. This function processes
* any incoming data - probably from other devices. So, based
* on cluster ID, perform the intended action.
*
* @param none
*
* @return none
*/
void SimonApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
uint8 id = 255;
if ( MY_ENDPOINT01 == pkt->endPoint )//7号端点
{
switch ( pkt->clusterId )
{
case 0x0001://1号员工--负责处理终端节点按键3按下发送过来的数据
//Uart_Send_String(pkt->cmd.Data,pkt->cmd.DataLength);
LS164_BYTE(pkt->cmd.Data[0]);
MYLED1 ^= 1;//LED翻转
break;
case 0x0002://2号员工--负责处理终端节点按键4按下发送过来的数据
//Uart_Send_String(pkt->cmd.Data,pkt->cmd.DataLength);
LS164_BYTE(pkt->cmd.Data[0]);
MYLED2 ^= 1;
break;
}
}
if ( MY_ENDPOINT02 == pkt->endPoint )//6号端点/房间
{
switch ( pkt->clusterId )
{
case CLUSTER_PHOTO_NODE://1号员工
//Uart_Send_String(pkt->cmd.Data,pkt->cmd.DataLength);
//LS164_BYTE(pkt->cmd.Data[0]);
//HalUARTWrite(MY_PORT_NUM,"Simonrn",7);
if(TYPE_PHOTO == pkt->cmd.Data[0])//如果是图像节点发送来的数据
{
MYLED3 ^= 1;//LED3翻转
id = pkt->cmd.Data[1];//获取节点在同类节点中的序号
gPhotoID = id;//缓存序号
//HalUARTWrite(MY_PORT_NUM,pkt->cmd.Data,pkt->cmd.DataLength);
//为了避免终端节点突然死机重新入网引起的数据中断错误需要判断新的网络地址和之前保存的是否一致
//此时在协调器PothoNode_AddrArr[id].exist非零,但终端节点的网络短地址可能发生改变
//如果不更新网络地址,则协调器反馈的信息将不能达到终端节点,从而引发错误
if((0 == PothoNode_AddrArr[id].exist) || (PothoNode_AddrArr[id].shortAddr != *((uint16 *)&(pkt->cmd.Data[2]))))
{
//((uint8 * )&(PothoNode_AddrArr[id].shortAddr))[0] = pkt->cmd.Data[5];//pkt->cmd.Data[4]<<8+ pkt->cmd.Data[5]);
//((uint8 * )&(PothoNode_AddrArr[id].shortAddr))[1] = pkt->cmd.Data[4];
/*每次数据到来都讲数据包里携带的网络短地址和端点缓存下来*/
PothoNode_AddrArr[id].shortAddr = *((uint16 *)&(pkt->cmd.Data[2]));//(pkt->cmd.Data[5]*256+ pkt->cmd.Data[4]);
PothoNode_AddrArr[id].endPoint = pkt->cmd.Data[4];
//表示已经缓存过该节点--现处于调试阶段--后期修改
//按理来说,这里的代码应该只在节点第一次发送数据给协调器的时候调用
PothoNode_AddrArr[id].exist = 1;
MYLED2 ^= 1;//协调器第一次收到某个节点发送的数据--翻转LED2
}
#if 0
//HalUARTWrite(MY_PORT_NUM,(uint8 *)PothoNode_AddrArr,PHOTO_ID_MAX*sizeof(AddrInfo_t));
//if((PothoNode_AddrArr[id].seqnb + 1) == (pkt->cmd.Data[2]<<8+ pkt->cmd.Data[3]))
//if( (((uint8 * )&(PothoNode_AddrArr[id].seqnb))[0] +1) == pkt->cmd.Data[3]
// && ((uint8 * )&(PothoNode_AddrArr[id].seqnb))[1] == pkt->cmd.Data[2] )
//if((PothoNode_AddrArr[id].seqnb + 1) == (pkt->cmd.Data[3]*256+ pkt->cmd.Data[2]))
if((PothoNode_AddrArr[id].seqnb + 1) == (*((uint16 *)&(pkt->cmd.Data[2]))))
{
HalUARTWrite(MY_PORT_NUM,pkt->cmd.Data,pkt->cmd.DataLength);
//osal_set_event( SimonApp_TaskID, SimonApp_RESPONSE_PHOTO_EVT );
PothoNode_AddrArr[id].seqnb++;
}
#endif
#if 1
//每次有数据到来,都直接将数据发送给上位机
//PothoNode_AddrArr[id].seqnb = *((uint16 *)&(pkt->cmd.Data[5]));
HalUARTWrite(MY_PORT_NUM,pkt->cmd.Data,pkt->cmd.DataLength);
//每次有数据到来,都给节点反馈信息
//osal_set_event( SimonApp_TaskID, SimonApp_RESPONSE_PHOTO_EVT );
ResponsePhotoNode();//直接反馈,不需要在进行事件轮询了--要快点
#endif
}
break;
}
}
}
/*********************************************************************
* @fn SimonApp_SendTheMessage
*
* @brief Send "the" message.
*
* @param none
*
* @return none
*/
void SimonApp_SendTheMessage( void )
{
char theMessageData[] = "Hello World";
if ( AF_DataRequest( &SimonApp_DstAddr, &SimonApp_epDesc,
SimonApp_CLUSTERID,
(byte)osal_strlen( theMessageData ) + 1,
(byte *)&theMessageData,
&SimonApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
{
// Successfully requested to be sent.
}
else
{
// Error occurred in request to send.
}
}
/*********************************************************************
*********************************************************************/
/*added by Simon*/
/*暂时没多大用处*/
static void rxCB(uint8 port,uint8 event)
{
#if 0 //串口回显测试用
uint8 tmp_len = 0;
osal_memset(gUartBuf,0,BUF_MAX);
tmp_len = HalUARTRead(MY_PORT_NUM,gUartBuf,5);
gUartBuf[tmp_len] = tmp_len;
gUartBuf[tmp_len+1] = 'r';
gUartBuf[tmp_len+2] = 'n';
//HalUARTWrite(MY_PORT_NUM,(uint8*)&tmp_len,1);//
if(osal_memcmp(gUartBuf,"12345",5))
{
HalUARTWrite(MY_PORT_NUM,(uint8*)&tmp_len,1);
HalUARTWrite(MY_PORT_NUM,gUartBuf,tmp_len+3);
}
#endif
static uint8 tmp_len = 0;
uint8 my_buf[1] = {0};
if ((event & (HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT)) &&!tmp_len)
{
if(!tmp_len)
{
tmp_len=HalUARTRead(MY_PORT_NUM,my_buf, 1);
}
if(tmp_len>0)
{
//HalUARTWrite(MY_PORT_NUM,(uint8*)&tmp_len,1);
//HalUARTWrite(MY_PORT_NUM,gUartBuf,tmp_len+3);
switch(my_buf[0])
{
case 1:
//osal_set_event( SimonApp_TaskID, SimonApp_RESPONSE_PHOTO_EVT );
break;
default:
break;
}
}
tmp_len=0;
}
}
static void ResponsePhotoNode(void)//给节点反馈信息
{
char theMessageData[1] = {1};//给节点发送一个1表示成功收到他的数据
//theMessageData[0] = PothoNode_AddrArr[id].seqnb
gResponseAddr.addrMode = (afAddrMode_t)Addr16Bit;
gResponseAddr.addr.shortAddr = PothoNode_AddrArr[gPhotoID].shortAddr;
// Take the first endpoint, Can be changed to search through endpoints
gResponseAddr.endPoint = PothoNode_AddrArr[gPhotoID].endPoint;
if ( AF_DataRequest( &gResponseAddr, &SimonApp_epDesc,
CLUSTER_PHOTO_NODE,
1,
(byte *)&theMessageData,//(uint8*)(&(PothoNode_AddrArr[gPhotoID].seqnb)),
&SimonApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
{
// Successfully requested to be sent.
}
else
{
// Error occurred in request to send.
osal_set_event( SimonApp_TaskID, SimonApp_RESPONSE_PHOTO_EVT );
}
}
ARM开发板向终端节点发送图片
#include "uart.h"
#define MAX_BUF 64
#define HDR_LEN 3
#define OPEN_PIC_ERR -2
#define MAX_SEC 5
const char begin_str[] = "begin";
const char end_str[] = "end";
char buf[MAX_BUF+HDR_LEN]={0};
char rcv_buf[MAX_BUF]={0};
fd_set inset,tempset;
struct timeval tv;
unsigned int seqnb;
unsigned int seqnb_ack;//留待以后扩展
int waitACK(int src_fd,int read_cnt)
{
int res = 0;
while(1)
{
memset(rcv_buf,0,MAX_BUF);
/*为了程序的健壮性,需要在主循环不断更新文件描述符集合以及等待时间*/
tempset = inset;
tv.tv_sec = MAX_SEC;
tv.tv_usec = 0;
res = select(src_fd + 1,&tempset,NULL,NULL,&tv);
/*3.3.1 规定时间内收到响应数据包继续往下执行*/
/*3.3.2 超时没有响应信息则重新发送当前缓冲区数据包*/
/*3.3.3 发生错误就退出程序给出提示信息*/
if(res == 0)
{
printf("time out n");
write(src_fd,buf,read_cnt+HDR_LEN);
continue;
}
else if (res < 0)
{
printf("select errorn");
exit(-1);
}
else
{
if(FD_ISSET(src_fd, &inset))
{
read(src_fd,rcv_buf,MAX_BUF);
//seqnb_ack++;
//seqnb_ack = (((unsigned char)(rcv_buf[1]))<<8) + ((unsigned char)(rcv_buf[0]));
//printf("%d from zigbee:%drn",seqnb,seqnb_ack);
//if(strcmp(rcv_buf,"OKrn") == 0)
memset(rcv_buf,0,MAX_BUF);
return 0;
}
}
}
}
/*************************************************************************/
/*| 1 | 1 | 2 | 1 | 2 | 1 | 64 |*/
/*-----------------------------------------------------------------------*/
/*| type | id | shortAddr| endpoint | sequence | len | Data |*/
/*************************************************************************/
int main(int argc,char ** argv)
{
int uart_fd = 0;
int pic_fd = 0;
int read_cnt = 0;
FD_ZERO(&inset);
seqnb = 0;
seqnb_ack = 0;
if(argc <2)
{
printf("too less args...n");
exit(-1);
}
/*0. 打开串口*/
uart_fd = open_uart(1);
if(uart_fd < 0)
{
perror("open_uart");
return OPEN_UART_ERR;
}
FD_SET(uart_fd,&inset);
/*等待时间初始化*/
tv.tv_sec = MAX_SEC;
tv.tv_usec = 0;
/*1. 配置串口*/
if(set_uart_config(uart_fd,115200,8,'N',1) < 0)
{
perror("set_uart_config");
return SET_UART_ERR;
}
/*2. 向串口写入开始发送数据包*/
memset(buf,0,MAX_BUF+HDR_LEN);
memset(rcv_buf,0,MAX_BUF);
#if 1
seqnb++;
buf[0] = seqnb%256;
buf[1] = seqnb/256;
read_cnt = strlen(begin_str);
buf[2] = read_cnt;
strcpy(buf+HDR_LEN,begin_str);
write(uart_fd,buf,read_cnt+HDR_LEN);
while(waitACK(uart_fd,read_cnt) != 0);
//sleep(MAX_SEC);
#endif
/*3. 传输图片*/
/*3.1. 打开图片*/
pic_fd = open((const char *)argv[1],O_RDONLY);
if(pic_fd < 0)
{
perror("open");
return OPEN_PIC_ERR;
}
/*3.2. 读取一部分数据到缓冲区*/
/*临时缓冲区清零*/
memset(buf,0,MAX_BUF+HDR_LEN);
while((read_cnt = read(pic_fd,buf+HDR_LEN,MAX_BUF)) > 0 )
{
seqnb++;
buf[0] = seqnb%256;
buf[1] = seqnb/256;
buf[2] = read_cnt;
/*3.3. 将当前缓冲区数据包写入串口*/
write(uart_fd,buf,read_cnt+HDR_LEN);
/*3.3. 等待接收端响应*/
while(waitACK(uart_fd,read_cnt) != 0);
/*临时缓冲区清零*/
memset(buf,0,MAX_BUF+HDR_LEN);
}
/*3.4. 数据是否读取完毕*/
/*3.4.1 没有读完,重复3.2至此*/
memset(buf,0,MAX_BUF+HDR_LEN);
memset(rcv_buf,0,MAX_BUF);
/*3.4.2 读取完毕,向串口写入发送完毕数据包*/
//sleep(MAX_SEC);
seqnb++;
buf[0] = seqnb%256;
buf[1] = seqnb/256;
read_cnt = strlen(end_str);
buf[2] = read_cnt;
strcpy(buf+HDR_LEN,end_str);
write(uart_fd,buf,read_cnt+HDR_LEN);
while(waitACK(uart_fd,read_cnt) != 0);
close(pic_fd);
close(uart_fd);
return 0;
}
最后
以上就是暴躁海燕为你收集整理的17 ZigBee小项目 终于完结了 day05的全部内容,希望文章能够帮你解决17 ZigBee小项目 终于完结了 day05所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复