AP_ONVIF: add initial wsdl2h generated header for onvif devicemgmt

This commit is contained in:
Siddharth Purohit 2021-06-04 09:22:20 +05:30 committed by Andrew Tridgell
parent 7c9a17b9fb
commit 45f58367d0
10 changed files with 48031 additions and 0 deletions

View File

@ -0,0 +1,377 @@
/*
* This file is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Code by Michael Oborne and Siddharth Bharat Purohit, Cubepilot Pty.
*/
#include "AP_ONVIF.h"
#include <AP_ONVIF/MediaBinding.nsmap>
#include "onvifhelpers.h"
// For ChibiOS we will use HW RND # generator
#include <stdlib.h> //rand()
#ifndef USERNAME
#define USERNAME "admin"
#endif
#ifndef PASSWORD
#define PASSWORD "admin"
#endif
#ifndef ONVIF_HOSTNAME
#define ONVIF_HOSTNAME "http://10.211.55.3:10000"
#endif
#define DEVICE_ENDPOINT ONVIF_HOSTNAME"/onvif/device_service"
#define MEDIA_ENDPOINT ONVIF_HOSTNAME"/onvif/media_service"
#define PTZ_ENDPOINT ONVIF_HOSTNAME"/onvif/ptz_service"
#ifndef PRINT
#define PRINT(fmt,args...) do {printf(fmt "\n", ## args); } while(0)
#endif
const char *wsse_PasswordDigestURI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest";
const char *wsse_Base64BinaryURI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary";
// static AP _ONVIF *_singleton;
extern const AP_HAL::HAL &hal;
bool AP_ONVIF::init()
{
srand ((time_t)(hal.util->get_hw_rtc()/1000000ULL));
soap = soap_new1(SOAP_XML_CANONICAL | SOAP_C_UTFSTRING);
soap->connect_timeout = soap->recv_timeout = soap->send_timeout = 30; // 30 sec
proxy_device = new DeviceBindingProxy(soap);
proxy_media = new MediaBindingProxy(soap);
proxy_ptz = new PTZBindingProxy(soap);
if (proxy_device == nullptr ||
proxy_media == nullptr ||
proxy_ptz == nullptr) {
AP_HAL::panic("AP_ONVIF: Failed to allocate gSOAP Proxy objects.");
return false;
}
/// TODO: Need to find a way to store this in parameter system
// or it could be just storage, we will see
proxy_device->soap_endpoint = DEVICE_ENDPOINT;
if (!probe_onvif_server()) {
PRINT("Failed to probe onvif server.");
return false;
}
if (!hal.scheduler->thread_create(FUNCTOR_BIND_MEMBER(&AP_ONVIF::update, void), "onvif",
4096, AP_HAL::Scheduler::PRIORITY_IO, 0)) {
PRINT("Failed to create onvif thread");
return false;
}
return true;
}
void AP_ONVIF::update()
{
while(true) {
float pan = pan_norm;
float tilt = tilt_norm;
// translate them into actual commands using cmd limits
pan = ((pan + 1) * (pan_tilt_limit_max.x - pan_tilt_limit_min.x)/2.0) + pan_tilt_limit_min.x;
tilt = ((tilt + 1) * (pan_tilt_limit_max.y - pan_tilt_limit_min.y)/2.0) + pan_tilt_limit_min.y;
PRINT("PAN: %f TILT: %f", pan, tilt);
// don't send the same request again
if (uint32_t(pan*100.0) != uint32_t(last_pan_cmd*100.0) || uint32_t(tilt*100.0) != uint32_t(last_tilt_cmd*100.0)) {
// actually send the command
set_absolutemove(pan, tilt, 0.0);
last_pan_cmd = pan;
last_tilt_cmd = tilt;
}
hal.scheduler->delay(100);
}
}
void AP_ONVIF::report_error()
{
PRINT("ONVIF ERROR:\n");
if (soap_check_state(soap)) {
PRINT("Error: soap struct state not initialized");
} else if (soap->error) {
const char **c, *v = NULL, *s, *d;
c = soap_faultcode(soap);
if (!*c) {
soap_set_fault(soap);
c = soap_faultcode(soap);
}
if (soap->version == 2) {
v = soap_fault_subcode(soap);
}
s = soap_fault_string(soap);
d = soap_fault_detail(soap);
PRINT("%s%d fault %s [%s]\n%s\nDetail: %s",(soap->version ? "SOAP 1." : "Error "),
(soap->version ? (int)soap->version : soap->error),
*c, (v ? v : "no subcode"), (s ? s : "[no reason]"),
(d ? d : "[no detail]"));
}
}
bool AP_ONVIF::probe_onvif_server()
{
_tds__GetDeviceInformation GetDeviceInformation;
_tds__GetDeviceInformationResponse GetDeviceInformationResponse;
set_credentials();
if (proxy_device->GetDeviceInformation(&GetDeviceInformation, GetDeviceInformationResponse)) {
PRINT("Failed to fetch Device Information");
report_error();
return false;
}
PRINT("Manufacturer: %s",GetDeviceInformationResponse.Manufacturer.c_str());
PRINT("Model: %s",GetDeviceInformationResponse.Model.c_str());
PRINT("FirmwareVersion: %s",GetDeviceInformationResponse.FirmwareVersion.c_str());
PRINT("SerialNumber: %s",GetDeviceInformationResponse.SerialNumber.c_str());
PRINT("HardwareId: %s",GetDeviceInformationResponse.HardwareId.c_str());
// get device capabilities and print media
_tds__GetCapabilities GetCapabilities;
_tds__GetCapabilitiesResponse GetCapabilitiesResponse;
set_credentials();
if (proxy_device->GetCapabilities(&GetCapabilities, GetCapabilitiesResponse)) {
PRINT("Failed to fetch Device Capabilities");
report_error();
return false;
}
if (!GetCapabilitiesResponse.Capabilities || !GetCapabilitiesResponse.Capabilities->Media) {
PRINT("Missing device capabilities info");
} else {
PRINT("XAddr: %s", GetCapabilitiesResponse.Capabilities->Media->XAddr.c_str());
if (GetCapabilitiesResponse.Capabilities->Media->StreamingCapabilities) {
if (GetCapabilitiesResponse.Capabilities->Media->StreamingCapabilities->RTPMulticast) {
PRINT("RTPMulticast: %s",(*GetCapabilitiesResponse.Capabilities->Media->StreamingCapabilities->RTPMulticast ? "yes" : "no"));
}
if (GetCapabilitiesResponse.Capabilities->Media->StreamingCapabilities->RTP_USCORETCP) {
PRINT("RTP_TCP: %s", (*GetCapabilitiesResponse.Capabilities->Media->StreamingCapabilities->RTP_USCORETCP ? "yes" : "no"));
}
if (GetCapabilitiesResponse.Capabilities->Media->StreamingCapabilities->RTP_USCORERTSP_USCORETCP) {
PRINT("RTP_RTSP_TCP: %s", (*GetCapabilitiesResponse.Capabilities->Media->StreamingCapabilities->RTP_USCORERTSP_USCORETCP ? "yes" : "no"));
}
}
}
// set the Media proxy endpoint to XAddr
proxy_media->soap_endpoint = MEDIA_ENDPOINT;
// get device profiles
_trt__GetProfiles GetProfiles;
_trt__GetProfilesResponse GetProfilesResponse;
set_credentials();
if (proxy_media->GetProfiles(&GetProfiles, GetProfilesResponse)){
PRINT("Failed to fetch profiles");
report_error();
return false;
}
if (GetProfilesResponse.Profiles.size()) {
PRINT("Profiles Received %lu", GetProfilesResponse.Profiles.size());
} else {
PRINT("Error: No Profiles Received");
return false;
}
// for each profile get snapshot
for (uint32_t i = 0; i < GetProfilesResponse.Profiles.size(); i++) {
PRINT("Profile name: %s", GetProfilesResponse.Profiles[i]->Name.c_str());
}
// Just use first one for now
profile_token = GetProfilesResponse.Profiles[0]->token;
proxy_ptz->soap_endpoint = PTZ_ENDPOINT;
// _tptz__GetServiceCapabilities GetCapabilities;
// _tptz__GetServiceCapabilitiesResponse GetCapabilitiesResponse;
// GetCapabilities.Category = tt__CapabilityCategory__PTZ;
// set_credentials();
// if (proxy_ptz->GetServiceCapabilities(&GetCapabilities, GetCapabilitiesResponse)) {
// PRINT("Failed to fetch PTZ Capabilities");
// report_error();
// return false;
// }
// if (!GetCapabilitiesResponse.Capabilities) {
// }
// GetCapabilitiesResponse.Capabilities->PTZ
// get PTZ Token
_tptz__GetConfigurations GetConfigurations;
_tptz__GetConfigurationsResponse GetConfigurationsResponse;
set_credentials();
if (proxy_ptz->GetConfigurations(&GetConfigurations, GetConfigurationsResponse)) {
PRINT("Failed to fetch Configurations");
report_error();
return false;
}
if (GetConfigurationsResponse.PTZConfiguration.size()) {
PRINT("PTZ Tokens Received");
} else {
PRINT("Error: No Profiles Received");
return false;
}
for (uint32_t i = 0; i < GetConfigurationsResponse.PTZConfiguration.size(); i++) {
PRINT("PTZ: %s", GetConfigurationsResponse.PTZConfiguration[i]->Name.c_str());
}
//GetConfigurationsResponse.PTZConfiguration[0]->token
pan_tilt_limit_max = Vector2f(GetConfigurationsResponse.PTZConfiguration[0]->PanTiltLimits->Range->XRange->Max,
GetConfigurationsResponse.PTZConfiguration[0]->PanTiltLimits->Range->YRange->Max);
pan_tilt_limit_min = Vector2f(GetConfigurationsResponse.PTZConfiguration[0]->PanTiltLimits->Range->XRange->Min,
GetConfigurationsResponse.PTZConfiguration[0]->PanTiltLimits->Range->YRange->Min);
zoom_min = GetConfigurationsResponse.PTZConfiguration[0]->ZoomLimits->Range->XRange->Min;
zoom_max = GetConfigurationsResponse.PTZConfiguration[0]->ZoomLimits->Range->XRange->Max;
PRINT("Pan: %f %f Tilt: %f %f", pan_tilt_limit_min.x, pan_tilt_limit_max.x,
pan_tilt_limit_min.y, pan_tilt_limit_max.y);
// Get PTZ status
_tptz__GetStatus GetStatus;
_tptz__GetStatusResponse GetStatusResponse;
GetStatus.ProfileToken = profile_token;
set_credentials();
if (proxy_ptz->GetStatus(&GetStatus, GetStatusResponse)) {
PRINT("Failed to recieve PTZ status");
return false;
}
if (GetStatusResponse.PTZStatus->Error) {
PRINT("ErrorStatus: %s", GetStatusResponse.PTZStatus->Error->c_str());
}
if (GetStatusResponse.PTZStatus->MoveStatus->PanTilt) {
PRINT("PTStatus: %d", *GetStatusResponse.PTZStatus->MoveStatus->PanTilt);
}
if (GetStatusResponse.PTZStatus->MoveStatus->Zoom) {
PRINT("ZoomStatus: %d", *GetStatusResponse.PTZStatus->MoveStatus->Zoom);
}
PRINT("Pan: %f Tilt: %f", GetStatusResponse.PTZStatus->Position->PanTilt->x,
GetStatusResponse.PTZStatus->Position->PanTilt->y);
PRINT("Zoom: %f", GetStatusResponse.PTZStatus->Position->Zoom->x);
soap_destroy(soap);
soap_end(soap);
return true;
}
void AP_ONVIF::rand_nonce(char *nonce, size_t noncelen)
{
size_t i;
uint32_t r = (uint32_t)(hal.util->get_hw_rtc()/1000000ULL);
(void)memcpy((void *)nonce, (const void *)&r, 4);
for (i = 4; i < noncelen; i += 4)
{
r = rand();
(void)memcpy((void *)(nonce + i), (const void *)&r, 4);
}
}
#define TEST_NONCE "LKqI6G/AikKCQrN0zqZFlg=="
#define TEST_TIME "2010-09-16T07:50:45Z"
#define TEST_PASS "userpassword"
#define TEST_RESULT "tuOSpGlFlIXsozq4HFNeeGeFLEI="
#define TEST 0
void AP_ONVIF::set_credentials()
{
soap_wsse_delete_Security(soap);
soap_wsse_add_Timestamp(soap, "Time", 60);
_wsse__Security *security = soap_wsse_add_Security(soap);
const char *created = soap_dateTime2s(soap, (time_t)(hal.util->get_hw_rtc()/1000000ULL));
char HA[SHA1_DIGEST_SIZE] {};
char HABase64fin[29] {};
char nonce[16], *nonceBase64;
sha1_ctx ctx;
uint16_t HABase64len;
char *HABase64enc;
uint16_t noncelen;
/* generate a nonce */
rand_nonce(nonce, 16);
sha1_begin(&ctx);
#if TEST
char* test_nonce = (char*)base64_decode((const unsigned char*)TEST_NONCE, strlen(TEST_NONCE), &noncelen);
sha1_hash((const unsigned char*)test_nonce, noncelen, &ctx);
sha1_hash((const unsigned char*)TEST_TIME, strlen(TEST_TIME), &ctx);
sha1_hash((const unsigned char*)TEST_PASS, strlen(TEST_PASS), &ctx);
nonceBase64 = (char*)base64_encode((unsigned char*)test_nonce, 16, &noncelen);
PRINT("Created:%s Hash64:%s", TEST_TIME, HABase64fin);
#else
sha1_hash((const unsigned char*)nonce, 16, &ctx);
sha1_hash((const unsigned char*)created, strlen(created), &ctx);
sha1_hash((const unsigned char*)PASSWORD, strlen(PASSWORD), &ctx);
nonceBase64 = (char*)base64_encode((unsigned char*)nonce, 16, &noncelen);
#endif
sha1_end((unsigned char*)HA, &ctx);
HABase64enc = (char*)base64_encode((unsigned char*)HA, SHA1_DIGEST_SIZE, &HABase64len);
if (HABase64len > 29) {
//things have gone truly bad time to panic
PRINT("Error: Invalid Base64 Encode!");
free(HABase64enc);
return;
}
memcpy(HABase64fin, HABase64enc, HABase64len);
if (soap_wsse_add_UsernameTokenText(soap, "Auth", USERNAME, HABase64fin)) {
report_error();
}
/* populate the remainder of the password, nonce, and created */
security->UsernameToken->Password->Type = (char*)wsse_PasswordDigestURI;
security->UsernameToken->Nonce = (struct wsse__EncodedString*)soap_malloc(soap, sizeof(struct wsse__EncodedString));
security->UsernameToken->Salt = NULL;
security->UsernameToken->Iteration = NULL;
if (!security->UsernameToken->Nonce) {
return;
}
soap_default_wsse__EncodedString(soap, security->UsernameToken->Nonce);
security->UsernameToken->Nonce->__item = nonceBase64;
security->UsernameToken->Nonce->EncodingType = (char*)wsse_Base64BinaryURI;
security->UsernameToken->wsu__Created = soap_strdup(soap, created);
}
bool AP_ONVIF::set_absolutemove(float x, float y, float z)
{
_tptz__AbsoluteMove AbsoluteMove;
_tptz__AbsoluteMoveResponse AbsoluteMoveResponse;
AbsoluteMove.Position = soap_new_tt__PTZVector(soap);
AbsoluteMove.Position->PanTilt = soap_new_tt__Vector2D(soap);
AbsoluteMove.Position->Zoom = soap_new_tt__Vector1D(soap);
AbsoluteMove.Position->PanTilt->x = constrain_float(x, pan_tilt_limit_min.x, pan_tilt_limit_max.x);
AbsoluteMove.Position->PanTilt->y = constrain_float(y, pan_tilt_limit_min.y, pan_tilt_limit_max.y);
AbsoluteMove.Position->Zoom->x = constrain_float(z, zoom_min, zoom_max);
AbsoluteMove.Speed = NULL;
AbsoluteMove.ProfileToken = profile_token;
// PRINT("Setting AbsoluteMove: %f %f %f", AbsoluteMove.Position->PanTilt->x,
// AbsoluteMove.Position->PanTilt->y,
// AbsoluteMove.Position->Zoom->x);
set_credentials();
if (proxy_ptz->AbsoluteMove(&AbsoluteMove, AbsoluteMoveResponse)) {
PRINT("Failed to sent AbsoluteMove cmd");
report_error();
soap_destroy(soap);
soap_end(soap);
return false;
}
soap_destroy(soap);
soap_end(soap);
return true;
}

View File

@ -0,0 +1,61 @@
/*
* This file is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Code by Michael Oborne and Siddharth Bharat Purohit, Cubepilot Pty.
*/
#pragma once
#include <AP_HAL/AP_HAL.h>
#include <AP_ONVIF/onvifDeviceBindingProxy.h>
#include <AP_ONVIF/onvifMediaBindingProxy.h>
#include <AP_ONVIF/onvifPTZBindingProxy.h>
#include <plugin/wsseapi-lite.h>
#include <AP_Math/AP_Math.h>
class AP_ONVIF {
public:
bool init();
void set_credentials();
bool set_absolutemove(float pan, float tilt, float zoom);
void set_pan_norm(float pan) { pan_norm = pan; }
void set_tilt_norm(float tilt) { tilt_norm = tilt; }
// get singleton instance
// static AP_ONVIF *get_singleton() { return _singleton; }
private:
void report_error();
bool probe_onvif_server();
void rand_nonce(char *nonce, size_t noncelen);
void update();
Vector2f pan_tilt_limit_min;
Vector2f pan_tilt_limit_max;
float pan_norm, tilt_norm;
float last_pan_cmd, last_tilt_cmd;
float zoom_min, zoom_max;
std::string profile_token;
struct soap *soap;
DeviceBindingProxy *proxy_device;
MediaBindingProxy *proxy_media;
PTZBindingProxy *proxy_ptz;
static AP_ONVIF *_singleton;
char* media_endpoint;
};
// namespace AP {
// AP_ONVIF *onvif();
// };

View File

@ -0,0 +1,199 @@
/*
* Base64 encoding/decoding (RFC1341)
* Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
/*
* This file is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Code by Siddharth Bharat Purohit
*/
#include "onvifhelpers.h"
static const uint8_t base64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const uint8_t base64url_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
/**
* base64_encode - Base64 encode
* @src: Data to be encoded
* @len: Length of the data to be encoded
* @out_len: Pointer to output length variable, or %nullptr if not used
* Returns: Allocated buffer of out_len bytes of encoded data,
* or %nullptr on failure
*
* Caller is responsible for freeing the returned buffer. Returned buffer is
* nul terminated to make it easier to use as a C string. The nul terminator is
* not included in out_len.
*/
uint8_t* base64_encode_global(const uint8_t *src, uint16_t len, uint16_t *out_len, const uint8_t* table, bool urlsafe)
{
uint8_t *out, *pos;
const uint8_t *end, *in;
uint16_t olen;
int16_t line_len;
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
if (!urlsafe) {
olen += olen / 72; /* line feeds */
}
olen++; /* nul termination */
if (olen < len) {
return nullptr; /* integer overflow */
}
out = (uint8_t*)malloc(olen);
if (out == nullptr) {
return nullptr;
}
end = src + len;
in = src;
pos = out;
line_len = 0;
while (end - in >= 3) {
*pos++ = table[in[0] >> 2];
*pos++ = table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
*pos++ = table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
*pos++ = table[in[2] & 0x3f];
in += 3;
// if (!urlsafe) {
// line_len += 4;
// if (line_len >= 72) {
// *pos++ = '\n';
// line_len = 0;
// }
// }
}
if (end - in) {
*pos++ = table[in[0] >> 2];
if (end - in == 1) {
*pos++ = table[(in[0] & 0x03) << 4];
if(!urlsafe) {
*pos++ = '=';
}
} else {
*pos++ = table[((in[0] & 0x03) << 4) |
(in[1] >> 4)];
*pos++ = table[(in[1] & 0x0f) << 2];
}
if (!urlsafe) {
*pos++ = '=';
}
line_len += 4;
}
// if (line_len && !urlsafe) {
// *pos++ = '\n';
// }
*pos = '\0';
if (out_len) {
*out_len = pos - out;
}
return out;
}
uint8_t* base64_encode(const uint8_t *src, uint16_t len, uint16_t *out_len)
{
return base64_encode_global(src, len, out_len, base64_table, false);
}
//Reference: https://tools.ietf.org/html/rfc4648#section-5
uint8_t* base64url_encode(const uint8_t *src, uint16_t len, uint16_t *out_len)
{
return base64_encode_global(src, len, out_len, base64url_table, true);
}
/**
* base64_decode - Base64 decode
* @src: Data to be decoded
* @len: Length of the data to be decoded
* @out_len: Pointer to output length variable
* Returns: Allocated buffer of out_len bytes of decoded data,
* or %nullptr on failure
*
* Caller is responsible for freeing the returned buffer.
*/
uint8_t* base64_decode(const uint8_t *src, uint16_t len, uint16_t *out_len)
{
uint8_t dtable[256], *out, *pos, block[4], tmp;
uint16_t i, count, olen;
int16_t pad = 0;
memset(dtable, 0x80, 256);
for (i = 0; i < sizeof(base64_table) - 1; i++) {
dtable[base64_table[i]] = (uint8_t) i;
}
dtable['='] = 0;
count = 0;
for (i = 0; i < len; i++) {
if (dtable[src[i]] != 0x80) {
count++;
}
}
if (count == 0 || count % 4) {
return nullptr;
}
olen = count / 4 * 3;
pos = out = (uint8_t*)malloc(olen);
if (out == nullptr) {
return nullptr;
}
count = 0;
for (i = 0; i < len; i++) {
tmp = dtable[src[i]];
if (tmp == 0x80) {
continue;
}
if (src[i] == '=') {
pad++;
}
block[count] = tmp;
count++;
if (count == 4) {
*pos++ = (block[0] << 2) | (block[1] >> 4);
*pos++ = (block[1] << 4) | (block[2] >> 2);
*pos++ = (block[2] << 6) | block[3];
count = 0;
if (pad) {
if (pad == 1) {
pos--;
} else if (pad == 2) {
pos -= 2;
} else {
/* Invalid padding */
free(out);
return nullptr;
}
break;
}
}
}
*out_len = pos - out;
return out;
}

View File

@ -0,0 +1,45 @@
#include <AP_HAL/AP_HAL.h>
#include <AP_ONVIF/AP_ONVIF.h>
// #include <DeviceBinding.nsmap>
// #include <MediaBinding.nsmap>
// #include <PTZBinding.nsmap>
void setup();
void loop();
const AP_HAL::HAL& hal = AP_HAL::get_HAL();
AP_ONVIF onvif;
void setup()
{
printf("AP_ONVIF library test\n");
if (!onvif.init()) {
AP_HAL::panic("Failed to initialise onvif");
}
}
void loop()
{
static float pan = 0.0, tilt = 0.0;
static bool move_up;
printf("Sending: %f %f\n", pan, tilt);
onvif.set_absolutemove(pan, tilt, 0);
if (pan < 1.0 && move_up) {
pan += 0.1;
tilt += 0.1;
} else if(pan > -1.0 && !move_up) {
pan -= 0.1;
tilt -= 0.1;
}
if (pan >= 1.0 && move_up) {
move_up = false;
}
if (pan <= -1.0 && !move_up) {
move_up = true;
}
hal.scheduler->delay(10000);
}
AP_HAL_MAIN();

View File

@ -0,0 +1,7 @@
#!/usr/bin/env python
# encoding: utf-8
def build(bld):
bld.ap_example(
use='ap',
)

View File

@ -0,0 +1,57 @@
/*
---------------------------------------------------------------------------
Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.
LICENSE TERMS
The free distribution and use of this software in both source and binary
form is allowed (with or without changes) provided that:
1. distributions of this source code include the above copyright
notice, this list of conditions and the following disclaimer;
2. distributions in binary form include the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other associated materials;
3. the copyright holder's name is not used to endorse products
built using this software without specific written permission.
ALTERNATIVELY, provided that this notice is retained in full, this product
may be distributed under the terms of the GNU General Public License (GPL),
in which case the provisions of the GPL apply INSTEAD OF those given above.
DISCLAIMER
This software is provided 'as is' with no explicit or implied warranties
in respect of its properties, including, but not limited to, correctness
and/or fitness for purpose.
---------------------------------------------------------------------------
Issue Date: 01/08/2005
*/
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/* Size of SHA1 digest */
#define SHA1_DIGEST_SIZE 20
/* type to hold the SHA1 context */
typedef struct
{ uint32_t count[2];
uint32_t hash[5];
uint32_t wbuf[16];
} sha1_ctx;
void sha1_begin(sha1_ctx ctx[1]);
void sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1]);
void sha1_end(unsigned char hval[], sha1_ctx ctx[1]);
void sha1(unsigned char hval[], const unsigned char data[], unsigned long len);
uint8_t* base64_encode(const uint8_t *src, uint16_t len, uint16_t *out_len);
uint8_t* base64_decode(const uint8_t *src, uint16_t len, uint16_t *out_len);

233
libraries/AP_ONVIF/sha1.cpp Normal file
View File

@ -0,0 +1,233 @@
/*
---------------------------------------------------------------------------
Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.
LICENSE TERMS
The free distribution and use of this software in both source and binary
form is allowed (with or without changes) provided that:
1. distributions of this source code include the above copyright
notice, this list of conditions and the following disclaimer;
2. distributions in binary form include the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other associated materials;
3. the copyright holder's name is not used to endorse products
built using this software without specific written permission.
ALTERNATIVELY, provided that this notice is retained in full, this product
may be distributed under the terms of the GNU General Public License (GPL),
in which case the provisions of the GPL apply INSTEAD OF those given above.
DISCLAIMER
This software is provided 'as is' with no explicit or implied warranties
in respect of its properties, including, but not limited to, correctness
and/or fitness for purpose.
---------------------------------------------------------------------------
Issue Date: 01/08/2005
This is a byte oriented version of SHA1 that operates on arrays of bytes
stored in memory.
*/
#include <string.h> /* for memcpy() etc. */
#include "onvifhelpers.h"
#define SHA1_BLOCK_SIZE 64
#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n)))
#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n)))
#define bswap_32(x) ((rotr32((x), 24) & 0x00ff00ff) | (rotr32((x), 8) & 0xff00ff00))
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define bsw_32(p,n) \
{ int _i = (n); while(_i--) ((uint32_t*)p)[_i] = bswap_32(((uint32_t*)p)[_i]); }
#elif __BYTE_ORDER == __BIG_ENDIAN
#define bsw_32(p,n)
#endif
#define SHA1_MASK (SHA1_BLOCK_SIZE - 1)
#if 0
#define ch(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
#define parity(x,y,z) ((x) ^ (y) ^ (z))
#define maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#else /* Discovered by Rich Schroeppel and Colin Plumb */
#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
#define parity(x,y,z) ((x) ^ (y) ^ (z))
#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y))))
#endif
/* Compile 64 bytes of hash data into SHA1 context. Note */
/* that this routine assumes that the byte order in the */
/* ctx->wbuf[] at this point is in such an order that low */
/* address bytes in the ORIGINAL byte stream will go in */
/* this buffer to the high end of 32-bit words on BOTH big */
/* and little endian systems */
#ifdef ARRAY
#define q(v,n) v[n]
#else
#define q(v,n) v##n
#endif
#define one_cycle(v,a,b,c,d,e,f,k,h) \
q(v,e) += rotr32(q(v,a),27) + \
f(q(v,b),q(v,c),q(v,d)) + k + h; \
q(v,b) = rotr32(q(v,b), 2)
#define five_cycle(v,f,k,i) \
one_cycle(v, 0,1,2,3,4, f,k,hf(i )); \
one_cycle(v, 4,0,1,2,3, f,k,hf(i+1)); \
one_cycle(v, 3,4,0,1,2, f,k,hf(i+2)); \
one_cycle(v, 2,3,4,0,1, f,k,hf(i+3)); \
one_cycle(v, 1,2,3,4,0, f,k,hf(i+4))
static void sha1_compile(sha1_ctx ctx[1])
{ uint32_t *w = ctx->wbuf;
#ifdef ARRAY
uint32_t v[5];
memcpy(v, ctx->hash, 5 * sizeof(uint32_t));
#else
uint32_t v0, v1, v2, v3, v4;
v0 = ctx->hash[0]; v1 = ctx->hash[1];
v2 = ctx->hash[2]; v3 = ctx->hash[3];
v4 = ctx->hash[4];
#endif
#define hf(i) w[i]
five_cycle(v, ch, 0x5a827999, 0);
five_cycle(v, ch, 0x5a827999, 5);
five_cycle(v, ch, 0x5a827999, 10);
one_cycle(v,0,1,2,3,4, ch, 0x5a827999, hf(15)); \
#undef hf
#define hf(i) (w[(i) & 15] = rotl32( \
w[((i) + 13) & 15] ^ w[((i) + 8) & 15] \
^ w[((i) + 2) & 15] ^ w[(i) & 15], 1))
one_cycle(v,4,0,1,2,3, ch, 0x5a827999, hf(16));
one_cycle(v,3,4,0,1,2, ch, 0x5a827999, hf(17));
one_cycle(v,2,3,4,0,1, ch, 0x5a827999, hf(18));
one_cycle(v,1,2,3,4,0, ch, 0x5a827999, hf(19));
five_cycle(v, parity, 0x6ed9eba1, 20);
five_cycle(v, parity, 0x6ed9eba1, 25);
five_cycle(v, parity, 0x6ed9eba1, 30);
five_cycle(v, parity, 0x6ed9eba1, 35);
five_cycle(v, maj, 0x8f1bbcdc, 40);
five_cycle(v, maj, 0x8f1bbcdc, 45);
five_cycle(v, maj, 0x8f1bbcdc, 50);
five_cycle(v, maj, 0x8f1bbcdc, 55);
five_cycle(v, parity, 0xca62c1d6, 60);
five_cycle(v, parity, 0xca62c1d6, 65);
five_cycle(v, parity, 0xca62c1d6, 70);
five_cycle(v, parity, 0xca62c1d6, 75);
#ifdef ARRAY
ctx->hash[0] += v[0]; ctx->hash[1] += v[1];
ctx->hash[2] += v[2]; ctx->hash[3] += v[3];
ctx->hash[4] += v[4];
#else
ctx->hash[0] += v0; ctx->hash[1] += v1;
ctx->hash[2] += v2; ctx->hash[3] += v3;
ctx->hash[4] += v4;
#endif
}
void sha1_begin(sha1_ctx ctx[1])
{
ctx->count[0] = ctx->count[1] = 0;
ctx->hash[0] = 0x67452301;
ctx->hash[1] = 0xefcdab89;
ctx->hash[2] = 0x98badcfe;
ctx->hash[3] = 0x10325476;
ctx->hash[4] = 0xc3d2e1f0;
}
/* SHA1 hash data in an array of bytes into hash buffer and */
/* call the hash_compile function as required. */
void sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1])
{ uint32_t pos = (uint32_t)(ctx->count[0] & SHA1_MASK),
space = SHA1_BLOCK_SIZE - pos;
const unsigned char *sp = data;
if((ctx->count[0] += len) < len)
++(ctx->count[1]);
while(len >= space) /* tranfer whole blocks if possible */
{
memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space);
sp += space; len -= space; space = SHA1_BLOCK_SIZE; pos = 0;
bsw_32(ctx->wbuf, SHA1_BLOCK_SIZE >> 2);
sha1_compile(ctx);
}
memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len);
}
/* SHA1 final padding and digest calculation */
void sha1_end(unsigned char hval[], sha1_ctx ctx[1])
{ uint32_t i = (uint32_t)(ctx->count[0] & SHA1_MASK);
/* put bytes in the buffer in an order in which references to */
/* 32-bit words will put bytes with lower addresses into the */
/* top of 32 bit words on BOTH big and little endian machines */
bsw_32(ctx->wbuf, (i + 3) >> 2);
/* we now need to mask valid bytes and add the padding which is */
/* a single 1 bit and as many zero bits as necessary. Note that */
/* we can always add the first padding byte here because the */
/* buffer always has at least one empty slot */
ctx->wbuf[i >> 2] &= 0xffffff80 << 8 * (~i & 3);
ctx->wbuf[i >> 2] |= 0x00000080 << 8 * (~i & 3);
/* we need 9 or more empty positions, one for the padding byte */
/* (above) and eight for the length count. If there is not */
/* enough space, pad and empty the buffer */
if(i > SHA1_BLOCK_SIZE - 9)
{
if(i < 60) ctx->wbuf[15] = 0;
sha1_compile(ctx);
i = 0;
}
else /* compute a word index for the empty buffer positions */
i = (i >> 2) + 1;
while(i < 14) /* and zero pad all but last two positions */
ctx->wbuf[i++] = 0;
/* the following 32-bit length fields are assembled in the */
/* wrong byte order on little endian machines but this is */
/* corrected later since they are only ever used as 32-bit */
/* word values. */
ctx->wbuf[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 29);
ctx->wbuf[15] = ctx->count[0] << 3;
sha1_compile(ctx);
/* extract the hash value as bytes in case the hash buffer is */
/* misaligned for 32-bit words */
for(i = 0; i < SHA1_DIGEST_SIZE; ++i)
hval[i] = (unsigned char)(ctx->hash[i >> 2] >> (8 * (~i & 3)));
}
void sha1(unsigned char hval[], const unsigned char data[], unsigned long len)
{ sha1_ctx cx[1];
sha1_begin(cx); sha1_hash(data, len, cx); sha1_end(hval, cx);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
cp ../../../modules/gsoap/gsoap/typemap.dat .
wsdl2h -O4 -P -x -o onvif.h \
http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl \
http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl \
http://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl
# http://www.onvif.org/onvif/ver10/events/wsdl/event.wsdl \
# http://www.onvif.org/onvif/ver10/deviceio.wsdl \
# http://www.onvif.org/onvif/ver20/imaging/wsdl/imaging.wsdl \
# http://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl \
# http://www.onvif.org/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl

View File

@ -0,0 +1,59 @@
#!/usr/bin/env python
# encoding: utf-8
'''
build generated bindings from bindings.desc for AP_Scripting
'''
from waflib.TaskGen import after_method, before_method, feature
import os
def configure(cfg):
"""
setup environment for mavlink header generator
"""
cfg.find_program('soapcpp2')
env = cfg.env
env.SOAP_DIR = cfg.srcnode.make_node('libraries/AP_ONVIF/soap').abspath()
env.SOAP_IMPORT = cfg.srcnode.make_node('modules/gsoap/gsoap/import').abspath()
cfg.env.AP_LIB_EXTRA_SOURCES['AP_ONVIF'] = []
cfg.env.AP_LIB_EXTRA_SOURCES['AP_ONVIF'] += ['onvifDeviceBindingProxy.cpp',
'onvifMediaBindingProxy.cpp',
'onvifPTZBindingProxy.cpp']
name = 'onvif'
cfg.env.AP_LIB_EXTRA_SOURCES['AP_ONVIF'] += ['{}C.cpp'.format(name)]
cfg.env.AP_LIB_EXTRA_SOURCES['AP_ONVIF'].append(cfg.srcnode.make_node('modules/gsoap/gsoap/stdsoap2.cpp').abspath())
cfg.env.AP_LIB_EXTRA_SOURCES['AP_ONVIF'].append(cfg.srcnode.make_node('modules/gsoap/gsoap/dom.cpp').abspath())
# cfg.env.AP_LIB_EXTRA_SOURCES['AP_ONVIF'].append(cfg.srcnode.make_node('modules/gsoap/gsoap/plugin/smdevp.c').abspath())
# cfg.env.AP_LIB_EXTRA_SOURCES['AP_ONVIF'].append(cfg.srcnode.make_node('modules/gsoap/gsoap/plugin/mecevp.c').abspath())
cfg.env.AP_LIB_EXTRA_SOURCES['AP_ONVIF'].append(cfg.srcnode.make_node('modules/gsoap/gsoap/plugin/wsseapi-lite.cpp').abspath())
cfg.env.AP_LIB_EXTRA_SOURCES['AP_ONVIF'].append(cfg.srcnode.make_node('modules/gsoap/gsoap/custom/struct_timeval.cpp').abspath())
cfg.env.INCLUDES += [cfg.srcnode.make_node('modules/gsoap/gsoap/').abspath()]
cfg.env.DEFINES += [
'SOAP_H_FILE=AP_ONVIF/onvifH.h',
]
env.append_value('GIT_SUBMODULES', 'gsoap')
def relpath(bld, node):
'''make a build relative path. This is needed for CI to pass on azure'''
blddir = bld.bldnode.make_node(".").abspath()
return os.path.relpath(node.abspath(), blddir)
def build(bld):
output_dir = bld.bldnode.make_node('libraries/AP_ONVIF').abspath()
gsoap_dir = bld.srcnode.make_node('modules/gsoap/gsoap').abspath()
import_dir = bld.srcnode.make_node('modules/gsoap/gsoap/import').abspath()
src = bld.srcnode.ant_glob('libraries/AP_ONVIF/soap/onvif.h')
name = 'onvif'
generated_cpp = [bld.bldnode.find_or_declare('libraries/AP_ONVIF/{}C.cpp'.format(name))]
generated_h = [bld.bldnode.find_or_declare('libraries/AP_ONVIF/{}H.h'.format(name))]
bld(
source=src,
rule="$(cd %s;%s -2 -Cp onvif -I%s:%s -j -x ../../${SRC})" % (output_dir,
bld.env.get_flat('SOAPCPP2'),
import_dir, gsoap_dir),
target=generated_cpp + generated_h,
group='dynamic_sources'
)