Merge branch 'PtzNew'

onereq
Matthew 3 months ago
commit ac357883ac

@ -385,6 +385,7 @@ add_library( # Sets the name of the library.
GPIOControl.cpp
MicroPhoto.cpp
PhoneDevice.cpp
PtzController.cpp
# PhoneDevice2.cpp
Camera.cpp
Camera2Reader.cpp
@ -447,6 +448,7 @@ add_library( # Sets the name of the library.
${TERM_CORE_ROOT}/Client/Terminal_NX.cpp
${TERM_CORE_ROOT}/Client/Terminal_ZJ.cpp
${TERM_CORE_ROOT}/Client/Terminal_NW.cpp
${TERM_CORE_ROOT}/Client/DataController.cpp
${TERM_CORE_ROOT}/Client/UpgradeReceiver.cpp
${TERM_CORE_ROOT}/Client/Database.cpp
${TERM_CORE_ROOT}/Client/SimulatorDevice.cpp

@ -565,6 +565,9 @@ CPhoneDevice::CPhoneDevice(JavaVM* vm, jobject service, const std::string& appPa
GpioControl::setCam3V3Enable(true);
GpioControl::setSpiPower(true);
#endif
m_ptzController = new PtzController(this);
m_ptzController->Startup();
}
CPhoneDevice::~CPhoneDevice()
@ -1551,6 +1554,7 @@ bool CPhoneDevice::TakePhotoWithNetCamera(IDevice::PHOTO_INFO& localPhotoInfo, c
// AutoEnv autoEnv(pThis->m_vm);
time_t ts = time(NULL);
uint32_t waitTime = localPhotoInfo.selfTestingTime;
#if 0
if(!GpioControl::GetSelftestStatus(waitTime))
{
m_isSelfTesting.store(true);
@ -1558,6 +1562,7 @@ bool CPhoneDevice::TakePhotoWithNetCamera(IDevice::PHOTO_INFO& localPhotoInfo, c
std::this_thread::sleep_for(std::chrono::milliseconds(waitTime));
m_isSelfTesting.store(false);
}
#endif
XYLOG(XYLOG_SEVERITY_DEBUG, "Ethernet Power ON");
@ -2085,11 +2090,13 @@ bool CPhoneDevice::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const vector<
}
else if (photoInfo.cameraType == CAM_TYPE_PLZ)
{
#if 0
XYLOG(XYLOG_SEVERITY_DEBUG, "PTZ PWR turned ON");
if(mPhotoInfo.scheduleTime == 0)
powerCtrlPtr = std::shared_ptr<PowerControl>(new PlzCameraPowerCtrl(mPhotoInfo.closeDelayTime));
else
powerCtrlPtr = std::shared_ptr<PowerControl>(new PlzCameraPowerCtrl(2));
#endif
}
res = true;
@ -2266,6 +2273,8 @@ bool CPhoneDevice::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const vector<
}
else if (mPhotoInfo.mediaType == 0 && (mPhotoInfo.cameraType == CAM_TYPE_PLZ))
{
m_ptzController->AddPhotoCommand(mPhotoInfo, mPath, mOsds);
#if 0
uint64_t wid_serial = RequestWakelock(0);
CPhoneDevice* pThis = this;
IDevice::PHOTO_INFO localPhotoInfo = mPhotoInfo;
@ -2300,6 +2309,7 @@ bool CPhoneDevice::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const vector<
});
t.detach();
#endif
}
else if ((mPhotoInfo.mediaType == XY_MEDIA_TYPE_STREAM || mPhotoInfo.mediaType == XY_MEDIA_TYPE_STREAM_OFF) && (mPhotoInfo.cameraType == CAM_TYPE_NET || mPhotoInfo.cameraType == CAM_TYPE_PLZ))
{
@ -4366,6 +4376,9 @@ void CPhoneDevice::ConvertDngToPng(const std::string& dngPath, const std::string
void CPhoneDevice::CameraCtrl(unsigned short waitTime, unsigned short delayTime, unsigned char channel, int cmdidx, unsigned char preset, const char *serfile, unsigned int baud, int addr)
{
m_ptzController->AddCommand(channel, cmdidx, 0, preset, serfile, baud, addr);
#if 0
if(GpioControl::GetSelftestStatus(waitTime) && GpioControl::GetCamerastatus()) {
CPhoneDevice *pThis = this;
string serfileStr(serfile);
@ -4382,6 +4395,7 @@ void CPhoneDevice::CameraCtrl(unsigned short waitTime, unsigned short delayTime,
});
ctrlThread.detach();
}
#endif
}
int CPhoneDevice::GetSerialPhoto(int devno, D_IMAGE_DEF *photo)

@ -31,6 +31,8 @@
#include <android/multinetwork.h>
#include "SensorsProtocol.h"
#include "PtzController.h"
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "error", __VA_ARGS__))
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "debug", __VA_ARGS__))
@ -168,6 +170,8 @@ class CPhoneDevice : public IDevice
{
public:
friend PtzController;
struct NETWORK
{
std::string iface;
@ -437,6 +441,8 @@ protected:
std::map<uint8_t, STREAMING_CONTEXT > m_streamings;
PtzController* m_ptzController;
};

@ -0,0 +1,384 @@
//
// Created by Matthew on 2025/3/5.
//
#include "PtzController.h"
#include "SensorsProtocol.h"
#include "GPIOControl.h"
#include "PhoneDevice.h"
#include "time.h"
#include <memory>
PtzController::PtzController(CPhoneDevice* pPhoneDevice) : m_pPhoneDevice(pPhoneDevice)
{
m_exit = false;
}
void PtzController::Startup()
{
m_thread = std::thread(PtzThreadProc, this);
}
void PtzController::PtzThreadProc(PtzController* pThis)
{
pThis->PtzProc();
}
void PtzController::AddCommand(uint8_t channel, int cmdidx, uint8_t bImageSize, uint8_t preset, const char *serfile, uint32_t baud, int addr)
{
SERIAL_CMD cmd = { 0 };
cmd.channel = channel;
cmd.preset = preset;
cmd.cmdidx = cmdidx;
cmd.bImageSize = bImageSize;
strcpy(cmd.serfile, serfile);
cmd.baud = baud;
cmd.addr = addr;
cmd.ts = time(NULL);
m_locker.lock();
m_cmds.push_back(cmd);
m_locker.unlock();
m_sem.release();
}
void PtzController::AddPhotoCommand(IDevice::PHOTO_INFO& photoInfo, const std::string& path, const std::vector<IDevice::OSD_INFO>& osds)
{
IDevice::SerialsPhotoParam param = { "", 0, 0 };
m_pPhoneDevice->GetPhotoSerialsParamCb(param);
SERIAL_CMD cmdPreset = { 0 };
time_t ts = time(NULL);
#if 1
// if (photoInfo.preset != 0 && photoInfo.preset != 0xFF)
{
cmdPreset.ts = photoInfo.selfTestingTime;
cmdPreset.delayTime = photoInfo.closeDelayTime;
cmdPreset.channel = photoInfo.channel;
cmdPreset.channel = photoInfo.preset;
cmdPreset.cmdidx = PHOTO_OPEN_POWER;
strcpy(cmdPreset.serfile, param.serfile);
cmdPreset.baud = param.baud;
cmdPreset.addr = param.addr;
}
#endif
SERIAL_CMD cmd = { 0 };
cmd.ts = ts;
cmd.delayTime = photoInfo.closeDelayTime;
cmd.channel = photoInfo.channel;
cmd.preset = photoInfo.preset;
cmd.cmdidx = Take_Photo;
cmd.bImageSize = photoInfo.resolution;
strcpy(cmd.serfile, param.serfile);
cmd.baud = param.baud;
cmd.addr = param.addr;
PtzPhotoParams* ppp = new PtzPhotoParams(photoInfo, path, osds);
cmd.photoParams.reset(ppp);
// cmd.delayTime;
// uint8_t bImageSize;
// char serfile[128];
// uint32_t baud;
// int addr;
m_locker.lock();
#if 1
if (cmdPreset.cmdidx != 0)
{
m_cmds.push_back(cmdPreset);
}
#endif
m_cmds.push_back(cmd);
m_locker.unlock();
m_sem.release();
m_sem.release();
}
void PtzController::ExitAndWait()
{
m_exit = true;
m_sem.release();
if (m_thread.joinable())
{
m_thread.join();
}
}
void PtzController::PtzProc()
{
PROC_PTZ_STATE state = PTZS_POWER_OFF;
SERIAL_CMD cmd;
PTZ_STATE ptz_state;
bool hasCmd = false;
int i=0;
char buffer[512];
std::shared_ptr<PowerControl> powerCtrl;
time_t selfTestingStartTime = 0;
time_t selfTestingWaitTime = 0;
time_t PTZ_preset_start_time = 0;
time_t PTZ_preset_wait_time = 0;
time_t close_delay_time = CAMERA_CLOSE_DELAYTIME;
time_t start_delay_time = 0;
time_t photo_move_preset_time = 0;
while(true)
{
m_sem.acquire();
if (m_exit)
{
break;
}
hasCmd = false;
m_locker.lock();
for (auto it = m_cmds.begin(); it != m_cmds.end(); ++it)
{
if ((state == PTZS_SELF_TESTING) || (PTZS_PHOTO_SELF_TESTING == state))
{
// find first non-taking-photo cmd
if (it->cmdidx != Take_Photo)
{
cmd = *it;
m_cmds.erase(it);
hasCmd = true;
break;
}
}
else
{
cmd = *it;
m_cmds.erase(it);
hasCmd = true;
break;
}
}
m_locker.unlock();
if (!hasCmd)
{
if ((state == PTZS_SELF_TESTING) || (PTZS_PHOTO_SELF_TESTING == state))
{
time_t timeout = time(NULL) - selfTestingStartTime;
if(timeout < 0)
selfTestingStartTime = time(NULL);
if (timeout >= selfTestingWaitTime)
{
XYLOG(XYLOG_SEVERITY_INFO, "超时(%d秒)未收到云台自检结束应答,状态改为空闲!", timeout);
state = PTZS_IDLE;
m_sem.release();
continue;
}
else
{
//if(timeout >= CAMERA_SELF_TEST_TIME)
{
XYLOG(XYLOG_SEVERITY_INFO, "开始查询云台自检状态timeout=%d秒", timeout);
if(0 == QueryPtzState(&ptz_state, QUERY_PTZ_STATE, cmd.serfile, cmd.baud, cmd.addr))
{
if(0 == ptz_state.ptz_status)
{
XYLOG(XYLOG_SEVERITY_INFO, "收到云台自检结束应答状态改为空闲timeout=%d秒", timeout);
state = PTZS_IDLE;
m_sem.release();
continue;
}
}
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
m_sem.release();
continue;
}
if(0 == start_delay_time)
{
;
}
else
{
if(time(NULL) - start_delay_time < 0)
{/* 防止等待关机期间,其他线程发生对时,改变了系统时间,导致长时间不会关摄像机电源*/
start_delay_time = time(NULL);
}
if(time(NULL) - start_delay_time >= close_delay_time)
{
XYLOG(XYLOG_SEVERITY_INFO, "摄像机空闲时间超过%d秒关闭摄像机", close_delay_time);
}
else
{
m_sem.release();
continue;
}
}
if (state == PTZS_POWER_OFF)
{
XYLOG(XYLOG_SEVERITY_INFO, "自动关机触发,摄像机本来就处于关机状态!");
// Do Nothing
}
else
{
XYLOG(XYLOG_SEVERITY_INFO, "自动关机触发通知云台准备关机state=%d", state);
for(i=0; i<3; i++)
{
if(0 == QueryPtzState(&ptz_state, NOTIFY_PTZ_CLOSE, cmd.serfile, cmd.baud, cmd.addr))
break;
}
powerCtrl.reset();
state = PTZS_POWER_OFF;
XYLOG(XYLOG_SEVERITY_INFO, "自动触发关闭云台电源state=%d", state);
}
start_delay_time = 0;
continue;
}
switch (cmd.cmdidx)
{
case Take_Photo:
{
if (state == PTZS_POWER_OFF)
{
if (!powerCtrl)
{
//powerCtrl = std::make_shared<PlzCameraPowerCtrl>(cmd.photoParams->mPhotoInfo.closeDelayTime);
powerCtrl = std::make_shared<PlzCameraPowerCtrl>(0);
selfTestingStartTime = time(NULL);
selfTestingWaitTime = cmd.photoParams->mPhotoInfo.selfTestingTime;
state = PTZS_PHOTO_SELF_TESTING;
XYLOG(XYLOG_SEVERITY_INFO, "1、收到拍照指令摄像机从关机状态改为自检状态");
m_locker.lock();
m_cmds.insert(m_cmds.begin(), cmd);
m_locker.unlock();
m_sem.release();
continue;
}
}
if(cmd.photoParams->mPhotoInfo.scheduleTime == 0)
{
start_delay_time = time(NULL);
memset(buffer, 0, sizeof(buffer));
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", localtime(&start_delay_time));
XYLOG(XYLOG_SEVERITY_INFO, "3、收到手动拍照指令state=%d%s", state, buffer);
}
else
XYLOG(XYLOG_SEVERITY_INFO, "2、收到自动拍照指令state=%d", state);
state = PTZS_TAKING_PHOTO;
if (cmd.preset != 0 && cmd.preset != 0xFF)
{
CameraPhotoCmd(0, cmd.channel, MOVE_PRESETNO, 0, cmd.preset, cmd.serfile, cmd.baud, cmd.addr);
PTZ_preset_start_time = time(NULL);
PTZ_preset_wait_time = MOVE_PRESET_WAIT_TIME;
XYLOG(XYLOG_SEVERITY_INFO, "摄像机拍照前开始调用预置点%dstate=%d", cmd.preset, state);
for(;;)
{
if(0 == QueryPtzState(&ptz_state, QUERY_PTZ_STATE, cmd.serfile, cmd.baud, cmd.addr))
{
if(0 == ptz_state.ptz_status)
{
XYLOG(XYLOG_SEVERITY_INFO, "摄像机拍照前调用预置点%d收到移动结束应答移动时长=%d秒 state=%d", cmd.preset, time(NULL)-PTZ_preset_start_time, state);
break;
}
}
if(time(NULL) - PTZ_preset_start_time >= PTZ_preset_wait_time)
{
XYLOG(XYLOG_SEVERITY_INFO, "摄像机拍照前调用预置点%d摄像机在%d秒内未收到调用预置点结束应答state=%d", cmd.preset, PTZ_preset_wait_time, state);
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
photo_move_preset_time = time(NULL);
}
}
m_pPhoneDevice->TakePhotoWithNetCamera(cmd.photoParams->mPhotoInfo, cmd.photoParams->mPath, cmd.photoParams->mOsds, powerCtrl);
state = PTZS_IDLE;
}
break;
case PHOTO_OPEN_POWER:
if (state == PTZS_POWER_OFF)
{
if (!powerCtrl)
{
powerCtrl = std::make_shared<PlzCameraPowerCtrl>(0);
selfTestingStartTime = time(NULL);
selfTestingWaitTime = 150;
state = PTZS_PHOTO_SELF_TESTING;
m_sem.release();
XYLOG(XYLOG_SEVERITY_INFO, "收到拍照指令开机,摄像机从关机状态改为自检状态!设置的自检等待时间%d秒", selfTestingWaitTime);
}
}
else
{
XYLOG(XYLOG_SEVERITY_INFO, "收到拍照指令开机摄像机处于state=%d", state);
}
break;
case OPEN_TOTAL:
if (state == PTZS_POWER_OFF)
{
if (!powerCtrl)
{
powerCtrl = std::make_shared<PlzCameraPowerCtrl>(0);
selfTestingStartTime = time(NULL);
selfTestingWaitTime = 150;
state = PTZS_SELF_TESTING;
m_sem.release();
XYLOG(XYLOG_SEVERITY_INFO, "收到手动开机指令,摄像机从关机状态改为自检状态!设置的自检等待时间%d秒", selfTestingWaitTime);
}
}
else
{
XYLOG(XYLOG_SEVERITY_INFO, "收到手动开机指令摄像机处于state=%d", state);
}
start_delay_time = time(NULL);
memset(buffer, 0, sizeof(buffer));
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", localtime(&start_delay_time));
XYLOG(XYLOG_SEVERITY_INFO, "收到手动打开摄像机指令刷新关机计时初始值state=%d%s", state, buffer);
break;
case CLOSE_TOTAL:
if (state == PTZS_POWER_OFF)
{
XYLOG(XYLOG_SEVERITY_INFO, "收到关机指令,摄像机本来就处于关机状态!");
// Do Nothing
}
else if(PTZS_PHOTO_SELF_TESTING == state)
{
XYLOG(XYLOG_SEVERITY_INFO, "在拍照自检过程中收到关机指令取消延时关机转到自动关机处理state=%d", state);
}
else
{
XYLOG(XYLOG_SEVERITY_INFO, "收到关机指令通知云台准备关机state=%d", state);
for(i=0; i<3; i++)
{
if(0 == QueryPtzState(&ptz_state, NOTIFY_PTZ_CLOSE, cmd.serfile, cmd.baud, cmd.addr))
break;
}
powerCtrl.reset();
state = PTZS_POWER_OFF;
XYLOG(XYLOG_SEVERITY_INFO, "关闭云台电源state=%d", state);
}
start_delay_time = 0;
break;
default:
{
start_delay_time = time(NULL);
memset(buffer, 0, sizeof(buffer));
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", localtime(&start_delay_time));
XYLOG(XYLOG_SEVERITY_INFO, "收到手动控制摄像机指令刷新关机计时初始值state=%d%s", state, buffer);
if(cmd.ts <= photo_move_preset_time)
{
XYLOG(XYLOG_SEVERITY_INFO, "丢弃拍照调预置点期间收到的控制云台指令,指令时间%ld 拍照时间%ldstate=%d", cmd.ts, photo_move_preset_time, state);
}
else
CameraPhotoCmd(cmd.ts, cmd.channel, cmd.cmdidx, 0, cmd.preset, cmd.serfile, cmd.baud, cmd.addr);
}
break;
}
}
}

@ -0,0 +1,98 @@
//
// Created by Matthew on 2025/3/5.
//
#ifndef MICROPHOTO_PTZCONTROLLER_H
#define MICROPHOTO_PTZCONTROLLER_H
#include <Buffer.h>
#include <thread>
#include <vector>
#include <memory>
#include <string>
#include <mutex>
#include <SemaphoreEx.h>
#include <Client/Device.h>
enum PROC_PTZ_STATE
{
PTZS_POWER_OFF = 0,
PTZS_IDLE = 1,
PTZS_SELF_TESTING = 2,
PTZS_MOVING = 3,
PTZS_TAKING_PHOTO = 4,
PTZS_PHOTO_SELF_TESTING = 5,
};
#define CAMERA_SELF_TEST_TIME 60 /* Camera self-test time (excluding PTZ self-test)*/
#define MOVE_PRESET_WAIT_TIME 20 /* Waiting for the maximum time for the PTZ to move to the preset position*/
#define CAMERA_CLOSE_DELAYTIME 120 /* Auto Power-Off Timer Setting After Manual Power-On (for Camera)*/
#define PHOTO_OPEN_POWER 16000
class PtzPhotoParams
{
public:
PtzPhotoParams(const IDevice::PHOTO_INFO& photoInfo, const std::string& path, const std::vector<IDevice::OSD_INFO>& osds) :
mPhotoInfo(photoInfo), mPath(path), mOsds(osds)
{
}
~PtzPhotoParams()
{
}
IDevice::PHOTO_INFO mPhotoInfo;
std::string mPath;
std::vector<IDevice::OSD_INFO> mOsds;
};
struct SERIAL_CMD
{
uint8_t channel;
uint8_t preset;
time_t ts;
int cmdidx;
uint32_t delayTime;
uint8_t bImageSize;
char serfile[128];
uint32_t baud;
int addr;
std::shared_ptr<PtzPhotoParams> photoParams;
};
class CPhoneDevice;
class PtzController
{
public:
PtzController(CPhoneDevice* pPhoneDevice);
void Startup();
// ();
void AddCommand(uint8_t channel, int cmdidx, uint8_t bImageSize, uint8_t preset, const char *serfile, uint32_t baud, int addr);
void AddPhotoCommand(IDevice::PHOTO_INFO& photoInfo, const std::string& path, const std::vector<IDevice::OSD_INFO>& osds);
void ExitAndWait();
protected:
static void PtzThreadProc(PtzController* pThis);
void PtzProc();
protected:
protected:
std::mutex m_locker;
std::vector<SERIAL_CMD> m_cmds;
CSemaphore m_sem;
bool m_exit;
std::thread m_thread;
CPhoneDevice* m_pPhoneDevice;
};
#endif //MICROPHOTO_PTZCONTROLLER_H

@ -23,13 +23,14 @@
#include <sys/time.h>
#include <pthread.h>
#include <AndroidHelper.h>
#include "AndroidHelper.h"
#include "SensorsProtocol.h"
//#include "Eint.h"
#include <algorithm>
pthread_mutex_t serial_mutex = PTHREAD_MUTEX_INITIALIZER; // 定义一个互斥锁
pthread_mutex_t camera_mutex = PTHREAD_MUTEX_INITIALIZER; // 定义一个互斥锁
pthread_mutex_t bd_mutex = PTHREAD_MUTEX_INITIALIZER; // 定义一个互斥锁
SIO_PARAM_SERIAL_DEF serialport[MAX_SERIAL_PORT_NUM];
@ -924,6 +925,7 @@ void Gm_FindAllSensorsCommand()
case PELCO_P_PROTOCOL: /* 摄像机协议*/
case SERIALCAMERA_PROTOCOL: /* 串口摄像机协议*/
break;
default:
break;
}
if (flag == -1)
@ -1485,7 +1487,7 @@ void CameraPhotoPortDataProcess(SIO_PARAM_SERIAL_DEF *curserial)
case 1: // 自检
if (0 == curserial->ptz_state.ptz_status)
sprintf(szbuf, "云台自检结束!");
else if (1 == curserial->ptz_state.ptz_status)
else if (0 < curserial->ptz_state.ptz_status)
sprintf(szbuf, "云台正在自检!");
else
sprintf(szbuf, "云台自检发生错误!");
@ -1494,9 +1496,9 @@ void CameraPhotoPortDataProcess(SIO_PARAM_SERIAL_DEF *curserial)
case 2: // 调用预置点
if (0 == curserial->ptz_state.ptz_status)
sprintf(szbuf, "调用预置位结束,云台处于所调预置位!");
else if (1 == curserial->ptz_state.ptz_status)
else if (0 < curserial->ptz_state.ptz_status)
sprintf(szbuf, "调用预置位,云台正在前往所调预置位位置!");
else if (2 == curserial->ptz_state.ptz_status)
else if (2 == (curserial->ptz_state.ptz_status & 0x0f))
sprintf(szbuf, "调用预置位时,机芯电源未打开!");
else
sprintf(szbuf, "调用预置位时,发生了错误,未正确执行!");
@ -1505,7 +1507,7 @@ void CameraPhotoPortDataProcess(SIO_PARAM_SERIAL_DEF *curserial)
case 3: // 一般状态
if (0 == curserial->ptz_state.ptz_status)
sprintf(szbuf, "云台处于静止状态!");
else if (1 == curserial->ptz_state.ptz_status)
else if (0 < curserial->ptz_state.ptz_status)
sprintf(szbuf, "云台正在运动!");
else
sprintf(szbuf, "云台发生错误!");
@ -2415,13 +2417,23 @@ void MakeShxyProtocolPollCommand(int portno, uint8_t cmdidx)
unsigned char CalLpc(unsigned char *msg, int len)
{
int i;
u_char retval = 0;
unsigned char retval = 0;
for (i = 0; i < len; i++)
retval += msg[i];
return retval;
}
unsigned char BDXorCheck(unsigned char *msg, int len)
{
int i;
unsigned char retval = 0;
for (i = 0; i < len; i++)
retval ^= msg[i];
return retval;
}
/***************************************************************
* *
***************************************************************/
@ -3264,14 +3276,17 @@ void GM_CameraSerialComRecv(SIO_PARAM_SERIAL_DEF *pPortParam)
recvlen = read(pPortParam->fd, &recvbuf[i], sizeof(recvbuf)-i);/* 在串口读取字符串 */
t1 = get_msec();
if(t1-t0 >= 350)
break;
{
i += recvlen;
break;
}
}
recvlen = i;
if (recvlen < 1)
return;
#if 1
sprintf(buf, "收到Camera, %d字节数据:", recvlen);
sprintf(buf, "收到BD, %d字节数据:", recvlen);
BytestreamLOG(0, buf, recvbuf, recvlen, 'I');
#endif
@ -3463,6 +3478,465 @@ int QueryPtzState(PTZ_STATE *ptz_state, int cmdidx, const char *serfile, unsign
pthread_mutex_unlock(&camera_mutex); // 解锁
return flag;
}
int Query_BDGNSS_Data(BD_GNSS_DATA *BD_data, int samptime, const char *serfile, unsigned int baud)
{
pthread_mutex_lock(&bd_mutex);
int flag = 0;
char szbuf[128], logbuf[128];
SIO_PARAM_SERIAL_DEF *cameraport=NULL;
if(NULL == BD_data)
return -1;
if(samptime < 5)
samptime = 5;
cameraport = (SIO_PARAM_SERIAL_DEF*)malloc(sizeof(SIO_PARAM_SERIAL_DEF));
cameraport->Retry = 0;
cameraport->RetryTime = 1000;
cameraport->WaitTime = 0;
cameraport->m_iRevStatus = 0;
cameraport->m_iRecvLen = 0;
cameraport->m_iNeedRevLength = 0;
cameraport->fd = -1;
memset(cameraport->m_au8RecvBuf, 0, RECVDATA_MAXLENTH); // 接收数据缓存区
ClearCameraCmdFormPollCmdBuf(cameraport);
flag = Gm_OpenCameraSerial(cameraport, serfile, baud);
#if 1
memset(szbuf, 0, sizeof(szbuf));
srdt.iLastGetPhotoNo = -1;
cameraport->SerialCmdidx = -1;
cameraport->FirstCmdTimeCnt = get_msec();
#endif
if(-1 == flag)
{
if(NULL != cameraport)
{
free(cameraport);
cameraport = NULL;
}
return -1;
}
if (0x00 == flag)
{
sprintf(szbuf, "北斗定位数据查询启动串口定时器!");
DebugLog(8, szbuf, 'I');
for (;;)
{
usleep(10);
//LOGW("polltime=%ldms", get_msec()-polltime);
//polltime = get_msec();
flag = GM_BdSerialTimer(cameraport);
if(get_msec() - cameraport->FirstCmdTimeCnt > samptime*1000)
{
DebugLog(8, "退出查询北斗定位数据流程!", 'V');
memmove((void*)BD_data, &cameraport->bd_data, sizeof(BD_GNSS_DATA));
break;
}
}
}
if(NULL != cameraport)
{
free(cameraport);
cameraport = NULL;
}
pthread_mutex_unlock(&bd_mutex); // 解锁
return flag;
}
int GM_BdSerialTimer(SIO_PARAM_SERIAL_DEF *pPortParam)
{
int flag = 0;
GM_BdSerialComRecv(pPortParam);
return flag;
}
void GM_BdSerialComRecv(SIO_PARAM_SERIAL_DEF *pPortParam)
{
int i, recvlen;
u_char recvbuf[RECVDATA_MAXLENTH];
char buf[RECVDATA_MAXLENTH+256];
int64_t t0, t1;
t0 = get_msec();
memset(recvbuf, 0, sizeof(recvbuf));
if (pPortParam->fd <= 0)
return;
i=0;
recvlen = 0;
memset(recvbuf, 0, sizeof(recvbuf));
for(;;)
{
i += recvlen;
recvlen = read(pPortParam->fd, &recvbuf[i], sizeof(recvbuf)-i);/* 在串口读取字符串 */
t1 = get_msec();
if(t1-t0 >= 350)
break;
}
recvlen = i;
if (recvlen < 1)
return;
#if 1
sprintf(buf, "收到BD, %d字节数据:%s", recvlen, recvbuf);
DebugLog(0, (char*)recvbuf, 'I');
#endif
BdRecvData(pPortParam, recvbuf, recvlen);
}
void BdRecvData(SIO_PARAM_SERIAL_DEF *pPortParam, u_char *buf, int len)
{
int i;
unsigned char bdxor=0, srcxor=0;
for (i = 0; i < len; i++)
{
switch (pPortParam->m_iRevStatus)
{
case 0: // 搜索起始符 '$'
pPortParam->m_iRecvLen = 0;
memset(pPortParam->m_au8RecvBuf, 0,sizeof(pPortParam->m_au8RecvBuf));
if ('$' == buf[i])
{
pPortParam->m_au8RecvBuf[pPortParam->m_iRecvLen++] = buf[i];
pPortParam->m_iRevStatus = 1; // 进入数据接收状态
}
break;
case 1: // 接收数据直到 '*'
if (pPortParam->m_iRecvLen >= RECVDATA_MAXLENTH)
{
// 缓冲区溢出,重置状态
pPortParam->m_iRevStatus = 0;
pPortParam->m_iRecvLen = 0;
break;
}
pPortParam->m_au8RecvBuf[pPortParam->m_iRecvLen++] = buf[i];
if (buf[i] == '*')
{
pPortParam->m_iRevStatus = 2; // 进入校验码接收状态
}
break;
case 2: // 接收校验码2字节十六进制和<CR><LF>
if (pPortParam->m_iRecvLen >= RECVDATA_MAXLENTH)
{
// 缓冲区溢出,重置状态
pPortParam->m_iRevStatus = 0;
pPortParam->m_iRecvLen = 0;
break;
}
pPortParam->m_au8RecvBuf[pPortParam->m_iRecvLen++] = buf[i];
// 检测到换行符0x0A检查前一个字符是否为回车符0x0D
if (buf[i] == 0x0A)
{
if (pPortParam->m_iRecvLen >= 5 &&
pPortParam->m_au8RecvBuf[pPortParam->m_iRecvLen - 2] == 0x0D)
{
// 提取校验码(*后的两个字符)
char hex_str[3] = {
(char)pPortParam->m_au8RecvBuf[pPortParam->m_iRecvLen - 4],
(char)pPortParam->m_au8RecvBuf[pPortParam->m_iRecvLen - 3],
'\0'
};
srcxor = (uint8_t)strtol(hex_str, NULL, 16);
// 计算校验值(从$后的第一个字符到*前的字符)
uint8_t calc_xor = BDXorCheck(&pPortParam->m_au8RecvBuf[1],pPortParam->m_iRecvLen - 6);// 长度 = 总长度 - ($ + *HH + \r\n)
if (srcxor == calc_xor)
{
BD_NMEA0183_PortDataProcess(pPortParam);
pPortParam->RevCmdFlag = 1;
}
// 重置状态,准备接收下一帧
pPortParam->m_iRevStatus = 0;
pPortParam->m_iRecvLen = 0;
}
else
{
// 格式错误,丢弃数据
pPortParam->m_iRevStatus = 0;
pPortParam->m_iRecvLen = 0;
}
}
break;
case 255:// 错误接收数据
default:
if (buf[i] == '$')
{
pPortParam->m_iRevStatus = 1;
pPortParam->m_iRecvLen = 1;
pPortParam->m_au8RecvBuf[0] = buf[i];
}
else
{
pPortParam->m_au8RecvBuf[pPortParam->m_iRecvLen++] = buf[i];
if (pPortParam->m_iRecvLen > 200)
{
pPortParam->m_iRecvLen = 0;
}
}
break;
}
}
}
/*
$BDRMC,023656.00,A,2240.61563,N,11359.86512,E,0.16,,140324,,,A,V*2C
$BDVTG,,,,,0.16,N,0.30,K,A*2F
$BDGGA,023656.00,2240.61563,N,11359.86512,E,1,23,0.7,96.53,M,-3.52,M,,*5B
$BDGSA,A,3,01,02,03,04,05,06,07,09,10,16,19,20,1.0,0.7,0.8,4*30
$BDGSV,6,1,23,01,45,125,38,02,46,235,40,03,61,189,46,04,32,112,37,1*7B
$BDGLL,2240.61563,N,11359.86512,E,023656.00,A,A*78
$BDZDA,023656.00,14,03,2024,00,00*71
$GPTXT,01,01,01,ANTENNA OPEN*25
GLLUTC
GSA使DOP
GSVSNR
RMC
VTG
ZDA:
TXT线
*/
void BD_NMEA0183_PortDataProcess(SIO_PARAM_SERIAL_DEF *curserial)
{
BD_NMEA0183_PROC_FUNC bd_nmea0183_call[] = {
{"$BDRMC",BD_get_BDRMC_data},/* 时间、日期、位置、速度*/
{"$BDVTG",NULL},/* 地面速度信息*/
{"$BDGGA",NULL},/* 时间、位置、定位类型*/
{"$BDGSA",NULL},/* 北斗接收机操作模式定位使用的卫星DOP 值 */
{"$BDGSV",NULL},/* 可见北斗卫星信息、仰角、方位角、信噪比SNR*/
{"$BDGLL",NULL},/* 经度、纬度、UTC 时间*/
{"$BDZDA",NULL},/* 时间、日期 */
{"$GPTXT",NULL},/* 用于天线状态检测*/
};/* irows*/
int i=0, irows;
char szbuf[512];
//char *cmd=NULL, *sourestr=NULL;
//RTUMSG rtumsg;
if(NULL == curserial)
return;
irows = sizeof(bd_nmea0183_call)/sizeof(BD_NMEA0183_PROC_FUNC);
memset(szbuf, 0, sizeof(szbuf));
//sprintf(szbuf, "rows = %d", irows);
DebugLog(0, (char*)curserial->m_au8RecvBuf, 'I');
#if 0
memset((void*)rtumsg.MsgData, 0, sizeof(rtumsg.MsgData));
memcpy((void*)rtumsg.MsgData, (void*)curserial->m_au8RecvBuf, curserial->m_iRecvLen);
rtumsg.MsgLen = curserial->m_iRecvLen;
/* 析出关键字符串*/
cmd = (char *)rtumsg.MsgData;
sourestr = strstr((char *)rtumsg.MsgData, ",");
*sourestr = 0;
sprintf(szbuf, "cmd_len = %d, cmd:%s", strlen(cmd), cmd);
DebugLog(0, szbuf, 'I');
#endif
for(i=0; i<irows; i++)
{
if(strstr((char *)curserial->m_au8RecvBuf, bd_nmea0183_call[i].cmd_name))
{
sprintf(szbuf, "cmd_name[%d]:%s", i, bd_nmea0183_call[i].cmd_name);
DebugLog(0, szbuf, 'I');
if(NULL != bd_nmea0183_call[i].recv_process)
bd_nmea0183_call[i].recv_process(curserial);
break;
}
}
if(i >= irows)
return;
}
int BD_get_BDRMC_data(SIO_PARAM_SERIAL_DEF *curserial)
{
const int UTC_TIME = 1;
const int STATUS = 2;
const int LAT = 3;
const int ULAT = 4;
const int LON = 5;
const int ULON = 6;
const int DATE = 9;
double dvalue;
int total_fields=0, ivalue;
char **result = NULL;
char buffer[128]; // 存储格式化时间的缓冲区
if(NULL == curserial)
return -1;
/*
1 $--RMC IDRMC --
2 UTCtime hhmmss.ss UTC
3 status V= A=
4 lat ddmm.mmmmm 2
5 uLat N-S-
6 lon dddmm.mmmmm 3
7 uLon E-W-西
8 spd
9 cog
10 date ddmmyy dd mm yy
11 mv
12 mvE E-W-西
13 mode [1]
14 navStatus V NMEA 4.1
15 CS 16 $*$*
16 <CR><LF> */
result = BD_NMEA0183_SplitString((char *)curserial->m_au8RecvBuf, &total_fields);
if(NULL == result)
return -1;
dvalue = ::atof(result[UTC_TIME]);
curserial->bd_data.UTC_time.tm_sec = (int)dvalue%100;
curserial->bd_data.UTC_time.tm_min = (int)dvalue/100%100;
curserial->bd_data.UTC_time.tm_hour = (int)dvalue/10000;
curserial->bd_data.ms_time = (dvalue - ((int)dvalue/1))*1000;
curserial->bd_data.status = result[STATUS][0];
dvalue = ::atof(result[LAT]);
curserial->bd_data.lat = ((int)dvalue/100)+(dvalue - ((int)dvalue/100*100))/60;
curserial->bd_data.uLat = result[ULAT][0];
dvalue = ::atof(result[LON]);
curserial->bd_data.lon = ((int)dvalue/100)+(dvalue - ((int)dvalue/100*100))/60;
curserial->bd_data.uLon = result[ULON][0];
ivalue = ::atoi(result[DATE]);
ALOGD("%d", ivalue);
curserial->bd_data.UTC_time.tm_mday = ivalue/10000;
ALOGD("D:%d", curserial->bd_data.UTC_time.tm_mday);
curserial->bd_data.UTC_time.tm_mon = ivalue/100%100-1;
ALOGD("M:%d", curserial->bd_data.UTC_time.tm_mon);
curserial->bd_data.UTC_time.tm_year = ivalue%100+100;
ALOGD("Y:%d", curserial->bd_data.UTC_time.tm_year);
::memset(buffer, 0, sizeof(buffer));
// 使用 strftime 格式化时间
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &curserial->bd_data.UTC_time);
DebugLog(0, (char*)buffer, 'I');
::sprintf(buffer, "ms:%d lat=%f ulat=%c", curserial->bd_data.ms_time, curserial->bd_data.lat, curserial->bd_data.uLat);
DebugLog(0, (char*)buffer, 'I');
::sprintf(buffer, "lon=%f ulon=%c, status=%c", curserial->bd_data.lon, curserial->bd_data.uLon, curserial->bd_data.status);
DebugLog(0, (char*)buffer, 'I');
// 释放内存
for (int i = 0; i < total_fields; ++i) free(result[i]);
free(result);
return 0;
}
char** BD_NMEA0183_SplitString(char *str, int *total_fields)
{
int max_fields, field_count = 0;
char **fields = NULL, **new_fields = NULL, **result = NULL;
char *copy = NULL, *p = NULL;
char szbuf[128];
if(NULL == str)
return NULL;
if(NULL == total_fields)
return NULL;
// 创建可修改的副本
copy = strdup(str);
memset(szbuf, 0, sizeof(szbuf));
if (!copy)
{
sprintf(szbuf, "内存分配失败\n");
DebugLog(0, szbuf, 'E');
return NULL;
}
// 初始字段数组大小
max_fields = MAX_FIELDS_NUM;
fields = (char**)malloc(max_fields * sizeof(char *));
if (!fields) {
free(copy);
sprintf(szbuf, "fields 内存分配失败\n");
DebugLog(0, szbuf, 'E');
return NULL;
}
field_count = 0;
fields[field_count] = copy; // 第一个字段起始
// 遍历字符串分割字段
for (p = copy; *p; ++p)
{
if (*p == ',')
{
*p = '\0'; // 结束当前字段
field_count++;
// 动态扩展数组
if (field_count >= max_fields) {
max_fields *= 2;
new_fields = (char**)realloc(fields, max_fields * sizeof(char *));
if (!new_fields) {
free(fields);
free(copy);
sprintf(szbuf, "new_fields 内存分配失败\n");
DebugLog(0, szbuf, 'E');
return NULL;
}
fields = new_fields;
}
fields[field_count] = p + 1; // 下一字段起始
}
}
*total_fields = field_count + 1; // 总字段数
// 复制字段到独立内存
result = (char **)malloc((*total_fields) * sizeof(char *));
if (!result)
{
free(fields);
free(copy);
sprintf(szbuf, "result 内存分配失败\n");
DebugLog(0, szbuf, 'E');
return NULL;
}
for (int i = 0; i < *total_fields; ++i) {
result[i] = strdup(fields[i]);
if (!result[i]) {
// 释放已分配内存
for (int j = 0; j < i; ++j) free(result[j]);
free(result);
free(fields);
free(copy);
sprintf(szbuf, "result 字段复制失败\n");
DebugLog(0, szbuf, 'E');
return NULL;
}
}
// 输出结果到日志
for (int i = 0; i < *total_fields; ++i)
{
sprintf(szbuf, "字段 %2d: %s\n", i + 1, result[i]);
DebugLog(0, szbuf, 'I');
}
// 释放内存
//for (int i = 0; i < total_fields; ++i) free(result[i]);
//free(result);
free(fields);
free(copy);
return result;
}
/* 串口启动接口函数 结束*/
/* 数据和图片采集数据返回函数 开始*/

@ -27,6 +27,7 @@
#define IOT_PARAM_WRITE 0xAE
#define IOT_PARAM_READ 0xAF
#define MAX_FIELDS_NUM 20 /* BD_NMEA0183单组字符串数据内含数据最大数量*/
#define MAX_SERIAL_DEV_NUM 25 /* 最大接串口传感器数量*/
#define MAX_SERIAL_PORT_NUM 5
#define MAX_DEV_VALUE_NUM 12 /* 一台装置最大的采样值数量*/
@ -39,6 +40,7 @@
#define PELCO_D_PROTOCOL 6 /* 摄像机Pelco_D协议序号*/
#define SERIALCAMERA_PROTOCOL 8 /* 串口摄像机协议序号*/
#define MUTIWEATHER_PROTOCOL 9 /*多合一气象*/
#define NMEA0183_PROTOCOL 10 /* 单一北斗NMEA0183标准协议*/
#define RESERVE2_PROTOCOL 17 /* 备用2协议序号*/
#define RESERVE4_PROTOCOL 19 /* 备用4协议序号*/
#define RESERVE5_PROTOCOL 20 /* 备用5协议序号*/
@ -126,6 +128,7 @@
#define OPEN_MODULE_POWER 10020 /* 打开机芯电源(1 有效)*/
#define NOTIFY_PTZ_CLOSE 10021 // 通知云台关闭
#define QUERY_PTZ_STATE 10022 // 查询云台状态
#define CLOSE_TOTAL 10040 /* 关闭总电源*/
#define SPEED_DOME_CAMERA 0 /* 球机摄像机*/
#define SERIAL_CAMERA 2 /* 串口摄像机a*/
@ -225,6 +228,38 @@ typedef struct
float x_coordinate; /* 云台所处位置水平方向坐标*/
float y_coordinate; /* 云台所处位置垂直方向坐标*/
} PTZ_STATE;
/*
$--RMC IDRMC --
2 UTCtime hhmmss.ss UTC
3 status
V=
A=
4 lat ddmm.mmmmm 2
5 uLat N-S-
6 lon dddmm.mmmm
m
3
7 uLon E-W-西
8 spd
9 cog
10 date ddmmyy dd mm yy
11 mv
12 mvE E-W-西
13 mode [1]
14 navStatus V
NMEA 4.1
15 CS 16 $*$**/
// 北斗卫星数据
typedef struct
{
struct tm UTC_time; /* UTC时间*/
int ms_time; /* 毫秒*/
double lat; /* 纬度,原值(前 2 字符表示度,后面的字符表示分)转换后为° */
char uLat; /* 纬度方向N-北S-南*/
double lon; /* 经度,原值(前 3 字符表示度,后面的字符表示分)转换后为°*/
char uLon; /* 经度'E'-东,'W'-西*/
char status; /* 'A'=数据有效 其他字符表示数据无效*/
} BD_GNSS_DATA;
typedef struct
{
@ -247,18 +282,27 @@ typedef struct
uint16_t ForceWaitCnt; /* 强制等待计数*/
uint8_t ReSendCmdFlag; /* 重发命令标志 */
uint8_t SendCmdFlag; /* 命令发送标志 */
uint8_t RevCmdFlag; /* 命令正常接收标志*/
uint8_t RevCmdFlag; /* 命令正常接收标志*/
//**********************************************************
int64_t lsendtime; /* 命令发送绝对时间计时(毫秒)*/
int cameraaddr; /* 摄像机地址*/
int64_t lsendtime; /* 命令发送绝对时间计时(毫秒)*/
int cameraaddr; /* 摄像机地址*/
int SerialCmdidx; /* 正在使用的串口发送命令的命令序号(-1:表示没有命令发送)
使*/
PHOTO_DEF image; /* 临时存储图片数据*/
PHOTO_DEF image; /* 临时存储图片数据*/
int64_t FirstCmdTimeCnt; /* 串口读取数据起始时间*/
PTZ_STATE ptz_state;
int sendptzstatecmd;
int sendptzstatecmd; // 查询命令次数控制
BD_GNSS_DATA bd_data;
} SIO_PARAM_SERIAL_DEF;
typedef const struct
{
//char *account; // 命令说明
char *cmd_name; // 命令名称
int (*recv_process)(SIO_PARAM_SERIAL_DEF *); /* urc数据处理*/
}BD_NMEA0183_PROC_FUNC;
//串口相关装置所有参数集中定义
typedef struct
{
@ -487,6 +531,23 @@ int GM_IsCloseCamera(SIO_PARAM_SERIAL_DEF *pPortParam);
int GM_CameraSerialTimer(SIO_PARAM_SERIAL_DEF *pPortParam);
int QueryPtzState(PTZ_STATE *ptz_state, int cmdidx, const char *serfile, unsigned int baud, int addr);
int Query_BDGNSS_Data(BD_GNSS_DATA *BD_data, int samptime, const char *serfile, unsigned int baud);
int GM_BdSerialTimer(SIO_PARAM_SERIAL_DEF *pPortParam);
void GM_BdSerialComRecv(SIO_PARAM_SERIAL_DEF *pPortParam);
void BdRecvData(SIO_PARAM_SERIAL_DEF *pPortParam, u_char *buf, int len);
unsigned char BDXorCheck(unsigned char *msg, int len);
void BD_NMEA0183_PortDataProcess(SIO_PARAM_SERIAL_DEF *curserial);
char** BD_NMEA0183_SplitString(char *str, int *total_fields);
int BD_get_BDRMC_data(SIO_PARAM_SERIAL_DEF *curserial);
#endif // __SENSOR_PROTOCOL_H__

Loading…
Cancel
Save