Qualcomm 远程信息处理 SDK - 用户指南(7)
4.2.2 接收数据
此示例应用程序演示了如何使用 C-V2X 无线电管理器 API 接收 C-V2X 数据。
- 为 ICv2xRadio 和 ICv2xRadioManager 方法创建回调方法
static Cv2xStatus gCv2xStatus;
static promise<ErrorCode> gCallbackPromise;
static shared_ptr<ICv2xRxSubscription> gRxSub;
static uint32_t gPacketsReceived = 0u;
static array<char, G_BUF_LEN> gBuf;
// Resets the global callback promise
static inline void resetCallbackPromise(void) {
gCallbackPromise = promise<ErrorCode>();
}
// Callback method for Cv2xRadioManager->requestCv2xStatus()
static void cv2xStatusCallback(Cv2xStatus status, ErrorCode error) {
if (ErrorCode::SUCCESS == error) {
gCv2xStatus = status;
}
gCallbackPromise.set_value(error);
}
// Callback method for Cv2xRadio->createRxSubscription() and Cv2xRadio->closeRxSubscription()
static void rxSubCallback(shared_ptr<ICv2xRxSubscription> rxSub, ErrorCode error) {
if (ErrorCode::SUCCESS == error) {
gRxSub = rxSub;
}
gCallbackPromise.set_value(error);
}
注意:我们还可以使用 Lambda 函数而不是定义全局范围回调。
- 获取 ICv2xRadioManager 实例的句柄
auto & cv2xFactory = Cv2xFactory::getInstance();
auto cv2xRadioManager = cv2xFactory.getCv2xRadioManager();
- 请求C-V2X状态
在尝试接收任何数据之前,我们希望验证 C-V2X RX 状态是否为“ACTIVE”。
// Get C-V2X status and make sure Rx is enabled
assert(Status::SUCCESS == cv2xRadioManager->requestCv2xStatus(cv2xStatusCallback));
assert(ErrorCode::SUCCESS == gCallbackPromise.get_future().get());
if (Cv2xStatusType::ACTIVE == gCv2xStatus.rxStatus) {
cout << "C-V2X RX status is active" << endl;
}
else {
cerr << "C-V2X RX is inactive" << endl;
return EXIT_FAILURE;
}
- 获取 C-V2X 无线电的句柄
auto cv2xRadio = cv2xRadioManager->getCv2xRadio(TrafficCategory::SAFETY_TYPE);
5.等待C-V2X无线电准备就绪
if (not cv2xRadio->isReady()) {
if (Status::SUCCESS == cv2xRadio->onReady().get()) {
cout << "C-V2X Radio is ready" << endl;
}
else {
cerr << "C-V2X Radio initialization failed." << endl;
return EXIT_FAILURE;
}
}
- 创建RX订阅并使用RX套接字接收数据
resetCallbackPromise();
assert(Status::SUCCESS == cv2xRadio->createRxSubscription(TrafficIpType::TRAFFIC_NON_IP,
RX_PORT_NUM,
rxSubCallback));
assert(ErrorCode::SUCCESS == gCallbackPromise.get_future().get());
// Read from the RX socket in a loop
for (uint32_t i = 0; i < NUM_TEST_ITERATIONS; ++i) {
// Receive from RX socket
sampleRx();
}
- 关闭RX订阅
我们在此示例中提供回调并检查其状态,但请注意它是可选的。
resetCallbackPromise();
assert(Status::SUCCESS == cv2xRadio->closeRxSubscription(gRxSub,
rxSubCallback));
assert(ErrorCode::SUCCESS == gCallbackPromise.get_future().get());
4.2.3 传输数据
此示例应用程序演示了如何使用 C-V2X 无线电管理器 API 发送 C-V2X 数据。
- 为 ICv2xRadio 和 ICv2xRadioManager 方法创建回调方法
static Cv2xStatus gCv2xStatus;
static promise<ErrorCode> gCallbackPromise;
static shared_ptr<ICv2xTxFlow> gSpsFlow;
static array<char, G_BUF_LEN> gBuf;
// Resets the global callback promise
static inline void resetCallbackPromise(void) {
gCallbackPromise = promise<ErrorCode>();
}
// Callback method for ICv2xRadioManager->requestCv2xStatus()
static void cv2xStatusCallback(Cv2xStatus status, ErrorCode error) {
if (ErrorCode::SUCCESS == error) {
gCv2xStatus = status;
}
gCallbackPromise.set_value(error);
}
// Callback method for ICv2xRadio->createTxSpsFlow()
static void createSpsFlowCallback(shared_ptr<ICv2xTxFlow> txSpsFlow,
shared_ptr<ICv2xTxFlow> unusedFlow,
ErrorCode spsError,
ErrorCode unusedError) {
if (ErrorCode::SUCCESS == spsError) {
gSpsFlow = txSpsFlow;
}
gCallbackPromise.set_value(spsError);
}
// Callback for ICv2xRadio->closeTxFlow()
static void closeFlowCallback(shared_ptr<ICv2xTxFlow> flow, ErrorCode error) {
gCallbackPromise.set_value(error);
}
注意:我们还可以使用 Lambda 函数而不是定义全局范围回调。
- 获取 ICv2xRadioManager 实例的句柄
// Get handle to Cv2xRadioManager
auto & cv2xFactory = Cv2xFactory::getInstance();
auto cv2xRadioManager = cv2xFactory.getCv2xRadioManager();
- 请求C-V2X状态
在尝试发送数据之前,我们希望验证 C-V2X TX 状态是否为 ACTIVE。
// Get C-V2X status and make sure Tx is enabled
assert(Status::SUCCESS == cv2xRadioManager->requestCv2xStatus(cv2xStatusCallback));
assert(ErrorCode::SUCCESS == gCallbackPromise.get_future().get());
if (Cv2xStatusType::ACTIVE == gCv2xStatus.txStatus) {
cout << "C-V2X TX status is active" << endl;
}
else {
cerr << "C-V2X TX is inactive" << endl;
return EXIT_FAILURE;
}
- 获取 C-V2X 无线电的句柄
auto cv2xRadio = cv2xRadioManager->getCv2xRadio(TrafficCategory::SAFETY_TYPE);
5.等待C-V2X无线电准备就绪
if (not cv2xRadio->isReady()) {
if (Status::SUCCESS == cv2xRadio->onReady().get()) {
cout << "C-V2X Radio is ready" << endl;
}
else {
cerr << "C-V2X Radio initialization failed." << endl;
return EXIT_FAILURE;
}
}
- 创建TX SPS流并使用TX套接字发送数据
// Set SPS parameters
SpsFlowInfo spsInfo;
spsInfo.priority = Priority::PRIORITY_2;
spsInfo.periodicity = Periodicity::PERIODICITY_100MS;
spsInfo.nbytesReserved = G_BUF_LEN;
spsInfo.autoRetransEnabledValid = true;
spsInfo.autoRetransEnabled = true;
// Create new SPS flow
resetCallbackPromise();
assert(Status::SUCCESS == cv2xRadio->createTxSpsFlow(TrafficIpType::TRAFFIC_NON_IP,
SPS_SERVICE_ID,
spsInfo,
SPS_SRC_PORT_NUM,
false,
0,
createSpsFlowCallback));
assert(ErrorCode::SUCCESS == gCallbackPromise.get_future().get());
// Send message in a loop
for (uint16_t i = 0; i < NUM_TEST_ITERATIONS; ++i) {
fillBuffer();
sampleSpsTx();
usleep(100000u);
}
- 关闭TX SPS流程
// Deregister SPS flow
resetCallbackPromise();
assert(Status::SUCCESS == cv2xRadio->closeTxFlow(gSpsFlow, closeFlowCallback));
assert(ErrorCode::SUCCESS == gCallbackPromise.get_future().get());
4.2.4 设置验证负载
此示例应用程序演示了如何使用 C-V2X 无线电管理器 API 来设置验证负载。
1.创建验证加载回调方法
static std::promise<telux::common::ErrorCode> gCallbackPromise;
// Callback method for Cv2xThrottleManager->setVerificationLoad()
static void cv2xsetVerificationLoadCallback(telux::common::ErrorCode error) {
std::cout << "error=" << static_cast<int>(error) << std::endl;
gCallbackPromise.set_value(error);
}
2.创建初始化状态回调方法
bool cv2xTmStatusUpdated = false;
telux::common::ServiceStatus cv2xTmStatus =
telux::common::ServiceStatus::SERVICE_UNAVAILABLE;
std::condition_variable cv;
std::mutex mtx;
auto statusCb = [&](telux::common::ServiceStatus status) {
std::lock_guard<std::mutex> lock(mtx);
cv2xTmStatusUpdated = true;
cv2xTmStatus = status;
cv.notify_all();
};
- 获取 ICv2xThrottleManager 实例的句柄
// Get handle to Cv2xThrottleManager
auto & cv2xFactory = Cv2xFactory::getInstance();
auto cv2xThrottleManager = cv2xFactory.getCv2xThrottleManager(statusCb);
4.等待油门管理器完成初始化
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck, [&] { return cv2xTmStatusUpdated; });
if (telux::common::ServiceStatus::SERVICE_AVAILABLE !=
cv2xTmStatus) {
std::cout << "Error: failed to initialize Cv2xThrottleManager." << std::endl;
return EXIT_FAILURE;
}
- 设置验证负载
cv2xThrottleManager->setVerificationLoad(load, cv2xsetVerificationLoadCallback);
if (telux::common::ErrorCode::SUCCESS != gCallbackPromise.get_future().get()) {
std::cout << "Error : failed to set verification load" << std::endl;
return EXIT_FAILURE;
} else {
std::cout << "set verification load success" << std::endl;
}
gCallbackPromise = std::promise<telux::common::ErrorCode>();
4.2.5 获取调整过滤率通知
此示例应用程序演示了如何通知客户端调整传入消息过滤率。
- 实现ICv2xThrottleManagerListener接口
class Cv2xTmListener : public ICv2xThrottleManagerListener {
public:
void onFilterRateAdjustment(int rate) override;
};
2.创建初始化状态回调方法
bool cv2xTmStatusUpdated = false;
telux::common::ServiceStatus cv2xTmStatus =
telux::common::ServiceStatus::SERVICE_UNAVAILABLE;
std::condition_variable cv;
std::mutex mtx;
std::cout << "Running TM app" << std::endl;
auto statusCb = [&](telux::common::ServiceStatus status) {
std::lock_guard<std::mutex> lock(mtx);
cv2xTmStatusUpdated = true;
cv2xTmStatus = status;
cv.notify_all();
};
- 获取 ICv2xThrottleManager 对象的句柄
// Get handle to Cv2xThrottleManager
auto & cv2xFactory = Cv2xFactory::getInstance();
auto cv2xThrottleManager = cv2xFactory.getCv2xThrottleManager(statusCb);
4.等待油门管理器完成初始化
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck, [&] { return cv2xTmStatusUpdated; });
if (telux::common::ServiceStatus::SERVICE_AVAILABLE !=
cv2xTmStatus) {
std::cout << "Error: failed to initialize Cv2xThrottleManager." << std::endl;
return EXIT_FAILURE;
}
5.实例化Cv2xTmListener
auto listener = std::make_shared<Cv2xTmListener>();
6.注册监听器
if (cv2xThrottleManager->registerListener(listener) !=
telux::common::Status::SUCCESS) {
std::cout << "Failed to register listener" << std::endl;
return EXIT_FAILURE;
}
7.等待过滤率调整通知
void Cv2xTmListener::onFilterRateAdjustment(int rate) {
std::cout << "Updated rate: " << rate << std::endl;
}
4.3 电话
4.3.1 拨打语音电话
此示例应用程序演示了如何进行语音呼叫。
- 实现ResponseCallback接口接收子系统初始化状态
std::promise<telux::common::ServiceStatus> cbProm = std::promise<telux::common::ServiceStatus>();
void initResponseCb(telux::common::ServiceStatus status) {
if(subSystemsStatus == SERVICE_AVAILABLE) {
std::cout << Call Manager subsystem is ready << std::endl;
} else if(subSystemsStatus == SERVICE_FAILED) {
std::cout << Call Manager subsystem initialization failed << std::endl;
}
cbProm.set_value(status);
}
- 获取PhoneFactory和Call Manager实例
auto &phoneFactory = PhoneFactory::getInstance();
auto callManager = phoneFactory.getCallManager(initResponseCb);
if(callManager == NULL) {
std::cout << " Failed to get Call Manager instance" << std::endl;
return -1;
}
- 等待呼叫管理器子系统准备就绪
telux::common::ServiceStatus status = cbProm.get_future().get();
if(status != SERVICE_AVAILABLE) {
std::cout << Unable to initialize Call Manager subsystem << std::endl;
return -1;
}
- (可选)实现 IMakeCallCallback 接口以接收拨号请求的响应
class DialCallback : public IMakeCallCallback {
public:
void DialCallback::makeCallResponse(ErrorCode error, std::shared_ptr<ICall> call) {
// will be invoked with response of makeCall operation
}
};
std::shared_ptr<DialCallback> dialCb = std::make_shared<DialCallback> ();
5. Send a dial request
- 发送拨号请求
if(callManager) {
std::string phoneNumber("+18989531755");
int phoneId = 1;
auto makeCallStatus = callManager->makeCall(phoneId, phoneNumber, dialCb);
std::cout << "Dial Call Status:" << (int)makeCallStatus << std::endl;
}
4.3.2 拨打紧急电话
此示例应用程序演示了如何拨打紧急 (E112) 语音呼叫。
- 实现ResponseCallback接口接收子系统初始化状态
std::promise<telux::common::ServiceStatus> cbProm = std::promise<telux::common::ServiceStatus>();
void initResponseCb(telux::common::ServiceStatus status) {
if(subSystemsStatus == SERVICE_AVAILABLE) {
std::cout << Call Manager subsystem is ready << std::endl;
} else if(subSystemsStatus == SERVICE_FAILED) {
std::cout << Call Manager subsystem initialization failed << std::endl;
}
cbProm.set_value(status);
}
- 获取PhoneFactory和Call Manager实例
auto &phoneFactory = PhoneFactory::getInstance();
auto callManager = phoneFactory.getCallManager(initResponseCb);
if(callManager == NULL) {
std::cout << " Failed to get Call Manager instance" << std::endl;
return -1;
}
- 等待呼叫管理器子系统准备就绪
telux::common::ServiceStatus status = cbProm.get_future().get();
if(status != SERVICE_AVAILABLE) {
std::cout << Unable to initialize Call Manager subsystem << std::endl;
return -1;
}
- (可选)实现 IMakeCallCallback 接口以接收拨号请求的响应
class DialCallback : public IMakeCallCallback {
public:
void DialCallback::makeCallResponse(ErrorCode error, std::shared_ptr<ICall> call) {
// will be invoked with response of makeCall operation
}
};
std::shared_ptr<DialCallback> dialCb = std::make_shared<DialCallback> ();
- 初始化eCall所需的数据,如eCallMsdData、emergencyCategory和eCallVariant
ECallCategory emergencyCategory = ECallCategory::VOICE_EMER_CAT_AUTO_ECALL;
ECallVariant eCallVariant = ECallVariant::ECALL_TEST;
// Instantiate ECallMsdData structure and populate it with valid information
// such as Latitude, Longitude etc.
// Parameter values mentioned here are for illustrative purposes only.
ECallMsdData eCallMsdData;
eCallMsdData.msdData.msdVersion = 2;
eCallMsdData.msdData.messageIdentifier = 1; // Each MSD message should bear a unique id
eCallMsdData.optionals.recentVehicleLocationN1Present = true;
eCallMsdData.optionals.recentVehicleLocationN2Present = true;
eCallMsdData.optionals.numberOfPassengersPresent = 2;
eCallMsdData.msdData.control.automaticAvtivation = true;
eCallMsdData.control.testCall = true;
eCallMsdData.control.positionCanBeTrusted = true;
eCallMsdData.control.vehicleType = ECallVehicleType::PASSENGER_VEHICLE_CLASS_M1;
eCallMsdData.msdData.vehicleIdentificationNumber.isowmi = "ECA";
eCallMsdData.msdData.vehicleIdentificationNumber.isovds = "LLEXAM";
eCallMsdData.msdData.vehicleIdentificationNumber.isovisModelyear = "P";
eCallMsdData.msdData.vehicleIdentificationNumber.isovisSeqPlant = "LE02013";
eCallMsdData.msdData.vehiclePropulsionStorage.gasolineTankPresent = true;
eCallMsdData.msdData.vehiclePropulsionStorage.dieselTankPresent = false;
eCallMsdData.vehiclePropulsionStorage.compressedNaturalGas = false;
eCallMsdData.vehiclePropulsionStorage.liquidPropaneGas = false;
eCallMsdData.vehiclePropulsionStorage.electricEnergyStorage = false;
eCallMsdData.vehiclePropulsionStorage.hydrogenStorage = false;
eCallMsdData.vehiclePropulsionStorage.otherStorage = false;
eCallMsdData.timestamp = 1367878452;
eCallMsdData.vehicleLocation.positionLatitude = 123;
eCallMsdData.vehicleLocation.positionLongitude = 1234;
eCallMsdData.msdData.vehicleDirection = 4;
eCallMsdData.recentVehicleLocationN1.latitudeDelta = false;
eCallMsdData.recentVehicleLocationN1.longitudeDelta = 0;
eCallMsdData.recentVehicleLocationN2.latitudeDelta = true;
eCallMsdData.recentVehicleLocationN2.longitudeDelta = 0;
- 发送 eCall 请求
int phoneId = 1;
if(callManager) {
auto makeCallStatus = callManager->makeECall(phoneId, eCallMsdData, emergencyCategory,
eCallVariant, dialCb);
std::cout << "Dial ECall Status:" << (int)makeCallStatus << std::endl;
}