Change C APIs to a unified string implementation (#6299)

Currently in the entire C API of WPILib we have ~8 different ways of handling strings. The C API actually isn't built for pure C callers (We don't actually have any of those). Instead, they're built for interop between languages like LabVIEW and C# which can talk to C API's directly.

For output parameters, the choice was fairly obvious. An output struct containing a const string pointer and a length makes the most sense. Its easy to use these from most other languages, and doesn't require special null termination handling. Freeing these is also easy, as if you ever receive one of these string structures, theres just a single function call to free it.

Input parameters are a bit more complex. To be used from pure C, and from LabVIEW, a null terminated string is the best in most cases. However, null terminated strings in general have a lot of downsides. Additionally, from LabVIEW there are other considerations around encoding that having a wrapper struct helps make a bit easier. From a language like C#, a wrapper struct is by far the easiest, as custom marshalling can make it trivial to marshal both UTF8 and UTF16 strings down.

The final consideration is its nice to have an identical concept for both input and output. It makes the rules fairly easy to understand.

WPILib will not have any APIs that manipulate a string allocated externally. This means WPI_String can be const, as across the boundary it is always const.
If a WPILib API takes a const WPI_String*, WPILib will not manipulate or attempt to free that string, and that string is treated as an input. It is up to the caller to handle that memory, WPILib will never hold onto that memory longer than the call.
If a WPILib API takes a WPI_String*, that string is an output. WPILib will allocate that API with WPI_AllocateString(), fill in the string, and return to the caller. When the caller is done with the string, they must free it with WPI_FreeString().
If an output struct contains a WPI_String member, that member is considered read only, and should not be explicitly freed. The caller should call the free function for that struct.
If an array of WPI_Strings are returned, each individual string is considered read only, and should not be explicitly freed. The free function for that array should be called by the caller.
If an input struct containing a WPI_String, or an input array of WPI_Strings is passed to WPILib, the individual strings will not be manipulated or freed by WPILib, and the caller owns and should free that memory.
Callbacks also follow these rules. The most common is a callback either getting passed a const WPI_String* or a struct containing a WPI_String. In both of these cases, the callback target should consider these strings read only, and not attempt to free them or manipulate them.
This commit is contained in:
Thad House
2024-05-13 05:35:14 -07:00
committed by GitHub
parent 178fe99f12
commit 4ce8f3f935
60 changed files with 990 additions and 914 deletions

View File

@@ -197,9 +197,9 @@ void SetSourceEnumPropertyChoices(CS_Source source, CS_Property property,
} // namespace cs
extern "C" {
void CS_NotifySourceError(CS_Source source, const char* msg,
void CS_NotifySourceError(CS_Source source, const struct WPI_String* msg,
CS_Status* status) {
return cs::NotifySourceError(source, msg, status);
return cs::NotifySourceError(source, wpi::to_string_view(msg), status);
}
void CS_SetSourceConnected(CS_Source source, CS_Bool connected,
@@ -207,17 +207,21 @@ void CS_SetSourceConnected(CS_Source source, CS_Bool connected,
return cs::SetSourceConnected(source, connected, status);
}
void CS_SetSourceDescription(CS_Source source, const char* description,
void CS_SetSourceDescription(CS_Source source,
const struct WPI_String* description,
CS_Status* status) {
return cs::SetSourceDescription(source, description, status);
return cs::SetSourceDescription(source, wpi::to_string_view(description),
status);
}
CS_Property CS_CreateSourceProperty(CS_Source source, const char* name,
CS_Property CS_CreateSourceProperty(CS_Source source,
const struct WPI_String* name,
enum CS_PropertyKind kind, int minimum,
int maximum, int step, int defaultValue,
int value, CS_Status* status) {
return cs::CreateSourceProperty(source, name, kind, minimum, maximum, step,
defaultValue, value, status);
return cs::CreateSourceProperty(source, wpi::to_string_view(name), kind,
minimum, maximum, step, defaultValue, value,
status);
}
CS_Property CS_CreateSourcePropertyCallback(
@@ -230,12 +234,12 @@ CS_Property CS_CreateSourcePropertyCallback(
}
void CS_SetSourceEnumPropertyChoices(CS_Source source, CS_Property property,
const char** choices, int count,
CS_Status* status) {
const struct WPI_String* choices,
int count, CS_Status* status) {
wpi::SmallVector<std::string, 8> vec;
vec.reserve(count);
for (int i = 0; i < count; ++i) {
vec.push_back(choices[i]);
vec.emplace_back(wpi::to_string_view(&choices[i]));
}
return cs::SetSourceEnumPropertyChoices(source, property, vec, status);
}

View File

@@ -634,55 +634,47 @@ std::vector<std::string> GetHttpCameraUrls(CS_Source source,
extern "C" {
CS_Source CS_CreateHttpCamera(const char* name, const char* url,
CS_Source CS_CreateHttpCamera(const struct WPI_String* name,
const struct WPI_String* url,
CS_HttpCameraKind kind, CS_Status* status) {
return cs::CreateHttpCamera(name, url, kind, status);
return cs::CreateHttpCamera(wpi::to_string_view(name),
wpi::to_string_view(url), kind, status);
}
CS_Source CS_CreateHttpCameraMulti(const char* name, const char** urls,
int count, CS_HttpCameraKind kind,
CS_Status* status) {
CS_Source CS_CreateHttpCameraMulti(const struct WPI_String* name,
const struct WPI_String* urls, int count,
CS_HttpCameraKind kind, CS_Status* status) {
wpi::SmallVector<std::string, 4> vec;
vec.reserve(count);
for (int i = 0; i < count; ++i) {
vec.push_back(urls[i]);
vec.emplace_back(wpi::to_string_view(&urls[i]));
}
return cs::CreateHttpCamera(name, vec, kind, status);
return cs::CreateHttpCamera(wpi::to_string_view(name), vec, kind, status);
}
CS_HttpCameraKind CS_GetHttpCameraKind(CS_Source source, CS_Status* status) {
return cs::GetHttpCameraKind(source, status);
}
void CS_SetHttpCameraUrls(CS_Source source, const char** urls, int count,
CS_Status* status) {
void CS_SetHttpCameraUrls(CS_Source source, const struct WPI_String* urls,
int count, CS_Status* status) {
wpi::SmallVector<std::string, 4> vec;
vec.reserve(count);
for (int i = 0; i < count; ++i) {
vec.push_back(urls[i]);
vec.emplace_back(wpi::to_string_view(&urls[i]));
}
cs::SetHttpCameraUrls(source, vec, status);
}
char** CS_GetHttpCameraUrls(CS_Source source, int* count, CS_Status* status) {
WPI_String* CS_GetHttpCameraUrls(CS_Source source, int* count,
CS_Status* status) {
auto urls = cs::GetHttpCameraUrls(source, status);
char** out =
static_cast<char**>(wpi::safe_malloc(urls.size() * sizeof(char*)));
WPI_String* out = WPI_AllocateStringArray(urls.size());
*count = urls.size();
for (size_t i = 0; i < urls.size(); ++i) {
out[i] = cs::ConvertToC(urls[i]);
cs::ConvertToC(&out[i], urls[i]);
}
return out;
}
void CS_FreeHttpCameraUrls(char** urls, int count) {
if (!urls) {
return;
}
for (int i = 0; i < count; ++i) {
std::free(urls[i]);
}
std::free(urls);
}
} // extern "C"

View File

@@ -1047,13 +1047,17 @@ int GetMjpegServerPort(CS_Sink sink, CS_Status* status) {
extern "C" {
CS_Sink CS_CreateMjpegServer(const char* name, const char* listenAddress,
int port, CS_Status* status) {
return cs::CreateMjpegServer(name, listenAddress, port, status);
CS_Sink CS_CreateMjpegServer(const struct WPI_String* name,
const struct WPI_String* listenAddress, int port,
CS_Status* status) {
return cs::CreateMjpegServer(wpi::to_string_view(name),
wpi::to_string_view(listenAddress), port,
status);
}
char* CS_GetMjpegServerListenAddress(CS_Sink sink, CS_Status* status) {
return ConvertToC(cs::GetMjpegServerListenAddress(sink, status));
void CS_GetMjpegServerListenAddress(CS_Sink sink, WPI_String* listenAddress,
CS_Status* status) {
cs::ConvertToC(listenAddress, cs::GetMjpegServerListenAddress(sink, status));
}
int CS_GetMjpegServerPort(CS_Sink sink, CS_Status* status) {

View File

@@ -184,16 +184,17 @@ uint64_t GrabSinkFrameTimeout(CS_Sink sink, WPI_RawFrame& image, double timeout,
} // namespace cs
extern "C" {
CS_Sink CS_CreateRawSink(const char* name, CS_Bool isCv, CS_Status* status) {
return cs::CreateRawSink(name, isCv, status);
CS_Sink CS_CreateRawSink(const struct WPI_String* name, CS_Bool isCv,
CS_Status* status) {
return cs::CreateRawSink(wpi::to_string_view(name), isCv, status);
}
CS_Sink CS_CreateRawSinkCallback(const char* name, CS_Bool isCv, void* data,
void (*processFrame)(void* data,
uint64_t time),
CS_Status* status) {
CS_Sink CS_CreateRawSinkCallback(
const struct WPI_String* name, CS_Bool isCv, void* data,
void (*processFrame)(void* data, uint64_t time), CS_Status* status) {
return cs::CreateRawSinkCallback(
name, isCv, [=](uint64_t time) { processFrame(data, time); }, status);
wpi::to_string_view(name), isCv,
[=](uint64_t time) { processFrame(data, time); }, status);
}
uint64_t CS_GrabRawSinkFrame(CS_Sink sink, struct WPI_RawFrame* image,

View File

@@ -53,9 +53,9 @@ void PutSourceFrame(CS_Source source, const WPI_RawFrame& image,
} // namespace cs
extern "C" {
CS_Source CS_CreateRawSource(const char* name, CS_Bool isCv,
CS_Source CS_CreateRawSource(const struct WPI_String* name, CS_Bool isCv,
const CS_VideoMode* mode, CS_Status* status) {
return cs::CreateRawSource(name, isCv,
return cs::CreateRawSource(wpi::to_string_view(name), isCv,
static_cast<const cs::VideoMode&>(*mode), status);
}

View File

@@ -242,18 +242,15 @@ void SetSinkEnabled(CS_Sink sink, bool enabled, CS_Status* status) {
} // namespace cs
extern "C" {
void CS_SetSinkDescription(CS_Sink sink, const char* description,
void CS_SetSinkDescription(CS_Sink sink, const struct WPI_String* description,
CS_Status* status) {
return cs::SetSinkDescription(sink, description, status);
return cs::SetSinkDescription(sink, wpi::to_string_view(description), status);
}
char* CS_GetSinkError(CS_Sink sink, CS_Status* status) {
void CS_GetSinkError(CS_Sink sink, struct WPI_String* error,
CS_Status* status) {
wpi::SmallString<128> buf;
auto str = cs::GetSinkError(sink, buf, status);
if (*status != 0) {
return nullptr;
}
return cs::ConvertToC(str);
cs::ConvertToC(error, cs::GetSinkError(sink, buf, status));
}
void CS_SetSinkEnabled(CS_Sink sink, CS_Bool enabled, CS_Status* status) {

View File

@@ -4,6 +4,8 @@
#include "cscore_c.h" // NOLINT(build/include_order)
#include <wpi/MemAlloc.h>
#include "c_util.h"
#include "cscore_cpp.h"
@@ -11,56 +13,53 @@ using namespace cs;
static void ConvertToC(CS_UsbCameraInfo* out, const UsbCameraInfo& in) {
out->dev = in.dev;
out->path = ConvertToC(in.path);
out->name = ConvertToC(in.name);
out->otherPaths = static_cast<char**>(
wpi::safe_malloc(in.otherPaths.size() * sizeof(char*)));
cs::ConvertToC(&out->path, in.path);
cs::ConvertToC(&out->name, in.name);
out->otherPaths = WPI_AllocateStringArray(in.otherPaths.size());
out->otherPathsCount = in.otherPaths.size();
for (size_t i = 0; i < in.otherPaths.size(); ++i) {
out->otherPaths[i] = cs::ConvertToC(in.otherPaths[i]);
cs::ConvertToC(&out->otherPaths[i], in.otherPaths[i]);
}
out->vendorId = in.vendorId;
out->productId = in.productId;
}
static void FreeUsbCameraInfo(CS_UsbCameraInfo* info) {
std::free(info->path);
std::free(info->name);
WPI_FreeString(&info->path);
WPI_FreeString(&info->name);
for (int i = 0; i < info->otherPathsCount; ++i) {
std::free(info->otherPaths[i]);
WPI_FreeString(&info->otherPaths[i]);
}
std::free(info->otherPaths);
}
extern "C" {
CS_Source CS_CreateUsbCameraDev(const char* name, int dev, CS_Status* status) {
return cs::CreateUsbCameraDev(name, dev, status);
CS_Source CS_CreateUsbCameraDev(const struct WPI_String* name, int dev,
CS_Status* status) {
return cs::CreateUsbCameraDev(wpi::to_string_view(name), dev, status);
}
CS_Source CS_CreateUsbCameraPath(const char* name, const char* path,
CS_Source CS_CreateUsbCameraPath(const struct WPI_String* name,
const struct WPI_String* path,
CS_Status* status) {
return cs::CreateUsbCameraPath(name, path, status);
return cs::CreateUsbCameraPath(wpi::to_string_view(name),
wpi::to_string_view(path), status);
}
void CS_SetUsbCameraPath(CS_Source source, const char* path,
void CS_SetUsbCameraPath(CS_Source source, const struct WPI_String* path,
CS_Status* status) {
cs::SetUsbCameraPath(source, path, status);
cs::SetUsbCameraPath(source, wpi::to_string_view(path), status);
}
char* CS_GetUsbCameraPath(CS_Source source, CS_Status* status) {
return ConvertToC(cs::GetUsbCameraPath(source, status));
void CS_GetUsbCameraPath(CS_Source source, WPI_String* path,
CS_Status* status) {
ConvertToC(path, cs::GetUsbCameraPath(source, status));
}
CS_UsbCameraInfo* CS_GetUsbCameraInfo(CS_Source source, CS_Status* status) {
auto info = cs::GetUsbCameraInfo(source, status);
if (*status != CS_OK) {
return nullptr;
}
CS_UsbCameraInfo* out = static_cast<CS_UsbCameraInfo*>(
wpi::safe_malloc(sizeof(CS_UsbCameraInfo)));
ConvertToC(out, info);
return out;
void CS_GetUsbCameraInfo(CS_Source source, CS_UsbCameraInfo* info,
CS_Status* status) {
auto info_cpp = cs::GetUsbCameraInfo(source, status);
ConvertToC(info, info_cpp);
}
CS_UsbCameraInfo* CS_EnumerateUsbCameras(int* count, CS_Status* status) {
@@ -89,7 +88,6 @@ void CS_FreeUsbCameraInfo(CS_UsbCameraInfo* info) {
return;
}
FreeUsbCameraInfo(info);
std::free(info);
}
} // extern "C"

View File

@@ -5,19 +5,16 @@
#ifndef CSCORE_C_UTIL_H_
#define CSCORE_C_UTIL_H_
#include <cstdlib>
#include <cstring>
#include <string_view>
#include <wpi/MemAlloc.h>
#include <wpi/string.h>
namespace cs {
inline char* ConvertToC(std::string_view in) {
char* out = static_cast<char*>(wpi::safe_malloc(in.size() + 1));
std::memmove(out, in.data(), in.size());
out[in.size()] = '\0';
return out;
inline void ConvertToC(struct WPI_String* output, std::string_view str) {
char* write = WPI_AllocateString(output, str.size());
std::memcpy(write, str.data(), str.size());
}
} // namespace cs

View File

@@ -19,12 +19,12 @@ static CS_Event ConvertToC(const cs::RawEvent& rawEvent) {
event.kind = static_cast<CS_EventKind>(static_cast<int>(rawEvent.kind));
event.source = rawEvent.sourceHandle;
event.sink = rawEvent.sinkHandle;
event.name = rawEvent.name.c_str();
cs::ConvertToC(&event.name, rawEvent.name);
event.mode = rawEvent.mode;
event.property = rawEvent.propertyHandle;
event.propertyKind = rawEvent.propertyKind;
event.value = rawEvent.value;
event.valueStr = rawEvent.valueStr.c_str();
cs::ConvertToC(&event.name, rawEvent.valueStr);
event.listener = rawEvent.listener;
return event;
}
@@ -53,13 +53,10 @@ CS_PropertyKind CS_GetPropertyKind(CS_Property property, CS_Status* status) {
return cs::GetPropertyKind(property, status);
}
char* CS_GetPropertyName(CS_Property property, CS_Status* status) {
void CS_GetPropertyName(CS_Property property, WPI_String* name,
CS_Status* status) {
wpi::SmallString<128> buf;
auto str = cs::GetPropertyName(property, buf, status);
if (*status != 0) {
return nullptr;
}
return cs::ConvertToC(str);
cs::ConvertToC(name, cs::GetPropertyName(property, buf, status));
}
int CS_GetProperty(CS_Property property, CS_Status* status) {
@@ -86,28 +83,24 @@ int CS_GetPropertyDefault(CS_Property property, CS_Status* status) {
return cs::GetPropertyDefault(property, status);
}
char* CS_GetStringProperty(CS_Property property, CS_Status* status) {
wpi::SmallString<128> buf;
auto str = cs::GetStringProperty(property, buf, status);
if (*status != 0) {
return nullptr;
}
return cs::ConvertToC(str);
}
void CS_SetStringProperty(CS_Property property, const char* value,
void CS_GetStringProperty(CS_Property property, WPI_String* value,
CS_Status* status) {
return cs::SetStringProperty(property, value, status);
wpi::SmallString<128> buf;
cs::ConvertToC(value, cs::GetStringProperty(property, buf, status));
}
char** CS_GetEnumPropertyChoices(CS_Property property, int* count,
CS_Status* status) {
void CS_SetStringProperty(CS_Property property, const struct WPI_String* value,
CS_Status* status) {
return cs::SetStringProperty(property, wpi::to_string_view(value), status);
}
WPI_String* CS_GetEnumPropertyChoices(CS_Property property, int* count,
CS_Status* status) {
auto choices = cs::GetEnumPropertyChoices(property, status);
char** out =
static_cast<char**>(wpi::safe_malloc(choices.size() * sizeof(char*)));
WPI_String* out = WPI_AllocateStringArray(choices.size());
*count = choices.size();
for (size_t i = 0; i < choices.size(); ++i) {
out[i] = cs::ConvertToC(choices[i]);
cs::ConvertToC(&out[i], choices[i]);
}
return out;
}
@@ -116,22 +109,15 @@ CS_SourceKind CS_GetSourceKind(CS_Source source, CS_Status* status) {
return cs::GetSourceKind(source, status);
}
char* CS_GetSourceName(CS_Source source, CS_Status* status) {
void CS_GetSourceName(CS_Source source, WPI_String* name, CS_Status* status) {
wpi::SmallString<128> buf;
auto str = cs::GetSourceName(source, buf, status);
if (*status != 0) {
return nullptr;
}
return cs::ConvertToC(str);
cs::ConvertToC(name, cs::GetSourceName(source, buf, status));
}
char* CS_GetSourceDescription(CS_Source source, CS_Status* status) {
void CS_GetSourceDescription(CS_Source source, WPI_String* description,
CS_Status* status) {
wpi::SmallString<128> buf;
auto str = cs::GetSourceDescription(source, buf, status);
if (*status != 0) {
return nullptr;
}
return cs::ConvertToC(str);
cs::ConvertToC(description, cs::GetSourceDescription(source, buf, status));
}
uint64_t CS_GetSourceLastFrameTime(CS_Source source, CS_Status* status) {
@@ -152,9 +138,10 @@ CS_Bool CS_IsSourceEnabled(CS_Source source, CS_Status* status) {
return cs::IsSourceEnabled(source, status);
}
CS_Property CS_GetSourceProperty(CS_Source source, const char* name,
CS_Property CS_GetSourceProperty(CS_Source source,
const struct WPI_String* name,
CS_Status* status) {
return cs::GetSourceProperty(source, name, status);
return cs::GetSourceProperty(source, wpi::to_string_view(name), status);
}
CS_Property* CS_EnumerateSourceProperties(CS_Source source, int* count,
@@ -209,13 +196,15 @@ CS_Bool CS_SetSourceFPS(CS_Source source, int fps, CS_Status* status) {
return cs::SetSourceFPS(source, fps, status);
}
CS_Bool CS_SetSourceConfigJson(CS_Source source, const char* config,
CS_Bool CS_SetSourceConfigJson(CS_Source source,
const struct WPI_String* config,
CS_Status* status) {
return cs::SetSourceConfigJson(source, config, status);
return cs::SetSourceConfigJson(source, wpi::to_string_view(config), status);
}
char* CS_GetSourceConfigJson(CS_Source source, CS_Status* status) {
return cs::ConvertToC(cs::GetSourceConfigJson(source, status));
void CS_GetSourceConfigJson(CS_Source source, WPI_String* config,
CS_Status* status) {
cs::ConvertToC(config, cs::GetSourceConfigJson(source, status));
}
CS_VideoMode* CS_EnumerateSourceVideoModes(CS_Source source, int* count,
@@ -286,27 +275,20 @@ CS_SinkKind CS_GetSinkKind(CS_Sink sink, CS_Status* status) {
return cs::GetSinkKind(sink, status);
}
char* CS_GetSinkName(CS_Sink sink, CS_Status* status) {
void CS_GetSinkName(CS_Sink sink, WPI_String* name, CS_Status* status) {
wpi::SmallString<128> buf;
auto str = cs::GetSinkName(sink, buf, status);
if (*status != 0) {
return nullptr;
}
return cs::ConvertToC(str);
cs::ConvertToC(name, cs::GetSinkName(sink, buf, status));
}
char* CS_GetSinkDescription(CS_Sink sink, CS_Status* status) {
void CS_GetSinkDescription(CS_Sink sink, WPI_String* description,
CS_Status* status) {
wpi::SmallString<128> buf;
auto str = cs::GetSinkDescription(sink, buf, status);
if (*status != 0) {
return nullptr;
}
return cs::ConvertToC(str);
cs::ConvertToC(description, cs::GetSinkDescription(sink, buf, status));
}
CS_Property CS_GetSinkProperty(CS_Sink sink, const char* name,
CS_Property CS_GetSinkProperty(CS_Sink sink, const struct WPI_String* name,
CS_Status* status) {
return cs::GetSinkProperty(sink, name, status);
return cs::GetSinkProperty(sink, wpi::to_string_view(name), status);
}
CS_Property* CS_EnumerateSinkProperties(CS_Sink sink, int* count,
@@ -320,13 +302,13 @@ CS_Property* CS_EnumerateSinkProperties(CS_Sink sink, int* count,
return out;
}
CS_Bool CS_SetSinkConfigJson(CS_Sink sink, const char* config,
CS_Bool CS_SetSinkConfigJson(CS_Sink sink, const struct WPI_String* config,
CS_Status* status) {
return cs::SetSinkConfigJson(sink, config, status);
return cs::SetSinkConfigJson(sink, wpi::to_string_view(config), status);
}
char* CS_GetSinkConfigJson(CS_Sink sink, CS_Status* status) {
return cs::ConvertToC(cs::GetSinkConfigJson(sink, status));
void CS_GetSinkConfigJson(CS_Sink sink, WPI_String* config, CS_Status* status) {
cs::ConvertToC(config, cs::GetSinkConfigJson(sink, status));
}
void CS_SetSinkSource(CS_Sink sink, CS_Source source, CS_Status* status) {
@@ -337,9 +319,10 @@ CS_Source CS_GetSinkSource(CS_Sink sink, CS_Status* status) {
return cs::GetSinkSource(sink, status);
}
CS_Property CS_GetSinkSourceProperty(CS_Sink sink, const char* name,
CS_Property CS_GetSinkSourceProperty(CS_Sink sink,
const struct WPI_String* name,
CS_Status* status) {
return cs::GetSinkSourceProperty(sink, name, status);
return cs::GetSinkSourceProperty(sink, wpi::to_string_view(name), status);
}
CS_Sink CS_CopySink(CS_Sink sink, CS_Status* status) {
@@ -360,7 +343,7 @@ void CS_SetListenerOnExit(void (*onExit)(void* data), void* data) {
CS_Listener CS_AddListener(void* data,
void (*callback)(void* data, const CS_Event* event),
int eventMask, int immediateNotify,
int eventMask, CS_Bool immediateNotify,
CS_Status* status) {
return cs::AddListener(
[=](const cs::RawEvent& rawEvent) {
@@ -435,8 +418,15 @@ double CS_GetTelemetryAverageValue(CS_Handle handle, CS_TelemetryKind kind,
return cs::GetTelemetryAverageValue(handle, kind, status);
}
void CS_SetLogger(CS_LogFunc func, unsigned int min_level) {
cs::SetLogger(func, min_level);
void CS_SetLogger(CS_LogFunc func, void* data, unsigned int min_level) {
cs::SetLogger(
[=](unsigned int level, const char* file, unsigned int line,
const char* msg) {
auto fileStr = wpi::make_string(file);
auto msgStr = wpi::make_string(msg);
func(data, level, &fileStr, line, &msgStr);
},
min_level);
}
void CS_SetDefaultLogger(unsigned int min_level) {
@@ -493,20 +483,6 @@ void CS_ReleaseEnumeratedSinks(CS_Sink* sinks, int count) {
std::free(sinks);
}
void CS_FreeString(char* str) {
std::free(str);
}
void CS_FreeEnumPropertyChoices(char** choices, int count) {
if (!choices) {
return;
}
for (int i = 0; i < count; ++i) {
std::free(choices[i]);
}
std::free(choices);
}
void CS_FreeEnumeratedProperties(CS_Property* properties, int count) {
std::free(properties);
}
@@ -515,29 +491,18 @@ void CS_FreeEnumeratedVideoModes(CS_VideoMode* modes, int count) {
std::free(modes);
}
char* CS_GetHostname(void) {
return cs::ConvertToC(cs::GetHostname());
void CS_GetHostname(struct WPI_String* hostname) {
cs::ConvertToC(hostname, cs::GetHostname());
}
char** CS_GetNetworkInterfaces(int* count) {
WPI_String* CS_GetNetworkInterfaces(int* count) {
auto interfaces = cs::GetNetworkInterfaces();
char** out =
static_cast<char**>(wpi::safe_malloc(interfaces.size() * sizeof(char*)));
WPI_String* out = WPI_AllocateStringArray(interfaces.size());
*count = interfaces.size();
for (size_t i = 0; i < interfaces.size(); ++i) {
out[i] = cs::ConvertToC(interfaces[i]);
cs::ConvertToC(&out[i], interfaces[i]);
}
return out;
}
void CS_FreeNetworkInterfaces(char** interfaces, int count) {
if (!interfaces) {
return;
}
for (int i = 0; i < count; ++i) {
std::free(interfaces[i]);
}
std::free(interfaces);
}
} // extern "C"

View File

@@ -8,6 +8,7 @@
#include <stdint.h>
#include <wpi/RawFrame.h>
#include <wpi/string.h>
#ifdef __cplusplus
#include <cstddef>
@@ -204,7 +205,7 @@ struct CS_Event {
CS_Sink sink;
// Source/sink/property name
const char* name;
struct WPI_String name;
// Fields for CS_SOURCE_VIDEOMODE_CHANGED event
CS_VideoMode mode;
@@ -213,7 +214,7 @@ struct CS_Event {
CS_Property property;
enum CS_PropertyKind propertyKind;
int value;
const char* valueStr;
struct WPI_String valueStr;
// Listener that was triggered
CS_Listener listener;
@@ -224,10 +225,10 @@ struct CS_Event {
*/
typedef struct CS_UsbCameraInfo {
int dev;
char* path;
char* name;
struct WPI_String path;
struct WPI_String name;
int otherPathsCount;
char** otherPaths;
struct WPI_String* otherPaths;
int vendorId;
int productId;
} CS_UsbCameraInfo;
@@ -238,34 +239,40 @@ typedef struct CS_UsbCameraInfo {
*/
enum CS_PropertyKind CS_GetPropertyKind(CS_Property property,
CS_Status* status);
char* CS_GetPropertyName(CS_Property property, CS_Status* status);
void CS_GetPropertyName(CS_Property property, struct WPI_String* name,
CS_Status* status);
int CS_GetProperty(CS_Property property, CS_Status* status);
void CS_SetProperty(CS_Property property, int value, CS_Status* status);
int CS_GetPropertyMin(CS_Property property, CS_Status* status);
int CS_GetPropertyMax(CS_Property property, CS_Status* status);
int CS_GetPropertyStep(CS_Property property, CS_Status* status);
int CS_GetPropertyDefault(CS_Property property, CS_Status* status);
char* CS_GetStringProperty(CS_Property property, CS_Status* status);
void CS_SetStringProperty(CS_Property property, const char* value,
void CS_GetStringProperty(CS_Property property, struct WPI_String* value,
CS_Status* status);
char** CS_GetEnumPropertyChoices(CS_Property property, int* count,
CS_Status* status);
void CS_SetStringProperty(CS_Property property, const struct WPI_String* value,
CS_Status* status);
struct WPI_String* CS_GetEnumPropertyChoices(CS_Property property, int* count,
CS_Status* status);
/** @} */
/**
* @defgroup cscore_source_create_cfunc Source Creation Functions
* @{
*/
CS_Source CS_CreateUsbCameraDev(const char* name, int dev, CS_Status* status);
CS_Source CS_CreateUsbCameraPath(const char* name, const char* path,
CS_Source CS_CreateUsbCameraDev(const struct WPI_String* name, int dev,
CS_Status* status);
CS_Source CS_CreateUsbCameraPath(const struct WPI_String* name,
const struct WPI_String* path,
CS_Status* status);
CS_Source CS_CreateHttpCamera(const char* name, const char* url,
CS_Source CS_CreateHttpCamera(const struct WPI_String* name,
const struct WPI_String* url,
enum CS_HttpCameraKind kind, CS_Status* status);
CS_Source CS_CreateHttpCameraMulti(const char* name, const char** urls,
int count, enum CS_HttpCameraKind kind,
CS_Source CS_CreateHttpCameraMulti(const struct WPI_String* name,
const struct WPI_String* urls, int count,
enum CS_HttpCameraKind kind,
CS_Status* status);
CS_Source CS_CreateCvSource(const char* name, const CS_VideoMode* mode,
CS_Status* status);
CS_Source CS_CreateCvSource(const struct WPI_String* name,
const CS_VideoMode* mode, CS_Status* status);
/** @} */
/**
@@ -273,15 +280,18 @@ CS_Source CS_CreateCvSource(const char* name, const CS_VideoMode* mode,
* @{
*/
enum CS_SourceKind CS_GetSourceKind(CS_Source source, CS_Status* status);
char* CS_GetSourceName(CS_Source source, CS_Status* status);
char* CS_GetSourceDescription(CS_Source source, CS_Status* status);
void CS_GetSourceName(CS_Source source, struct WPI_String* name,
CS_Status* status);
void CS_GetSourceDescription(CS_Source source, struct WPI_String* description,
CS_Status* status);
uint64_t CS_GetSourceLastFrameTime(CS_Source source, CS_Status* status);
void CS_SetSourceConnectionStrategy(CS_Source source,
enum CS_ConnectionStrategy strategy,
CS_Status* status);
CS_Bool CS_IsSourceConnected(CS_Source source, CS_Status* status);
CS_Bool CS_IsSourceEnabled(CS_Source source, CS_Status* status);
CS_Property CS_GetSourceProperty(CS_Source source, const char* name,
CS_Property CS_GetSourceProperty(CS_Source source,
const struct WPI_String* name,
CS_Status* status);
CS_Property* CS_EnumerateSourceProperties(CS_Source source, int* count,
CS_Status* status);
@@ -299,9 +309,11 @@ CS_Bool CS_SetSourcePixelFormat(CS_Source source,
CS_Bool CS_SetSourceResolution(CS_Source source, int width, int height,
CS_Status* status);
CS_Bool CS_SetSourceFPS(CS_Source source, int fps, CS_Status* status);
CS_Bool CS_SetSourceConfigJson(CS_Source source, const char* config,
CS_Bool CS_SetSourceConfigJson(CS_Source source,
const struct WPI_String* config,
CS_Status* status);
char* CS_GetSourceConfigJson(CS_Source source, CS_Status* status);
void CS_GetSourceConfigJson(CS_Source source, struct WPI_String* config,
CS_Status* status);
CS_VideoMode* CS_EnumerateSourceVideoModes(CS_Source source, int* count,
CS_Status* status);
CS_Sink* CS_EnumerateSourceSinks(CS_Source source, int* count,
@@ -330,9 +342,12 @@ void CS_SetCameraExposureManual(CS_Source source, int value, CS_Status* status);
* @defgroup cscore_usbcamera_cfunc UsbCamera Source Functions
* @{
*/
void CS_SetUsbCameraPath(CS_Source source, const char* path, CS_Status* status);
char* CS_GetUsbCameraPath(CS_Source source, CS_Status* status);
CS_UsbCameraInfo* CS_GetUsbCameraInfo(CS_Source source, CS_Status* status);
void CS_SetUsbCameraPath(CS_Source source, const struct WPI_String* path,
CS_Status* status);
void CS_GetUsbCameraPath(CS_Source source, struct WPI_String* path,
CS_Status* status);
void CS_GetUsbCameraInfo(CS_Source source, CS_UsbCameraInfo* info,
CS_Status* status);
/** @} */
/**
@@ -341,38 +356,43 @@ CS_UsbCameraInfo* CS_GetUsbCameraInfo(CS_Source source, CS_Status* status);
*/
enum CS_HttpCameraKind CS_GetHttpCameraKind(CS_Source source,
CS_Status* status);
void CS_SetHttpCameraUrls(CS_Source source, const char** urls, int count,
CS_Status* status);
char** CS_GetHttpCameraUrls(CS_Source source, int* count, CS_Status* status);
void CS_SetHttpCameraUrls(CS_Source source, const struct WPI_String* urls,
int count, CS_Status* status);
struct WPI_String* CS_GetHttpCameraUrls(CS_Source source, int* count,
CS_Status* status);
/** @} */
/**
* @defgroup cscore_frame_source_cfunc Frame Source Functions
* @{
*/
void CS_NotifySourceError(CS_Source source, const char* msg, CS_Status* status);
void CS_NotifySourceError(CS_Source source, const struct WPI_String* msg,
CS_Status* status);
void CS_SetSourceConnected(CS_Source source, CS_Bool connected,
CS_Status* status);
void CS_SetSourceDescription(CS_Source source, const char* description,
void CS_SetSourceDescription(CS_Source source,
const struct WPI_String* description,
CS_Status* status);
CS_Property CS_CreateSourceProperty(CS_Source source, const char* name,
CS_Property CS_CreateSourceProperty(CS_Source source,
const struct WPI_String* name,
enum CS_PropertyKind kind, int minimum,
int maximum, int step, int defaultValue,
int value, CS_Status* status);
void CS_SetSourceEnumPropertyChoices(CS_Source source, CS_Property property,
const char** choices, int count,
CS_Status* status);
const struct WPI_String* choices,
int count, CS_Status* status);
/** @} */
/**
* @defgroup cscore_sink_create_cfunc Sink Creation Functions
* @{
*/
CS_Sink CS_CreateMjpegServer(const char* name, const char* listenAddress,
int port, CS_Status* status);
CS_Sink CS_CreateCvSink(const char* name, enum WPI_PixelFormat pixelFormat,
CS_Status* status);
CS_Sink CS_CreateCvSinkCallback(const char* name,
CS_Sink CS_CreateMjpegServer(const struct WPI_String* name,
const struct WPI_String* listenAddress, int port,
CS_Status* status);
CS_Sink CS_CreateCvSink(const struct WPI_String* name,
enum WPI_PixelFormat pixelFormat, CS_Status* status);
CS_Sink CS_CreateCvSinkCallback(const struct WPI_String* name,
enum WPI_PixelFormat pixelFormat, void* data,
void (*processFrame)(void* data, uint64_t time),
CS_Status* status);
@@ -383,18 +403,21 @@ CS_Sink CS_CreateCvSinkCallback(const char* name,
* @{
*/
enum CS_SinkKind CS_GetSinkKind(CS_Sink sink, CS_Status* status);
char* CS_GetSinkName(CS_Sink sink, CS_Status* status);
char* CS_GetSinkDescription(CS_Sink sink, CS_Status* status);
CS_Property CS_GetSinkProperty(CS_Sink sink, const char* name,
void CS_GetSinkName(CS_Sink sink, struct WPI_String* name, CS_Status* status);
void CS_GetSinkDescription(CS_Sink sink, struct WPI_String* description,
CS_Status* status);
CS_Property CS_GetSinkProperty(CS_Sink sink, const struct WPI_String* name,
CS_Status* status);
CS_Property* CS_EnumerateSinkProperties(CS_Sink sink, int* count,
CS_Status* status);
void CS_SetSinkSource(CS_Sink sink, CS_Source source, CS_Status* status);
CS_Property CS_GetSinkSourceProperty(CS_Sink sink, const char* name,
CS_Property CS_GetSinkSourceProperty(CS_Sink sink,
const struct WPI_String* name,
CS_Status* status);
CS_Bool CS_SetSinkConfigJson(CS_Sink sink, const char* config,
CS_Bool CS_SetSinkConfigJson(CS_Sink sink, const struct WPI_String* config,
CS_Status* status);
char* CS_GetSinkConfigJson(CS_Sink sink, CS_Status* status);
void CS_GetSinkConfigJson(CS_Sink sink, struct WPI_String* config,
CS_Status* status);
CS_Source CS_GetSinkSource(CS_Sink sink, CS_Status* status);
CS_Sink CS_CopySink(CS_Sink sink, CS_Status* status);
void CS_ReleaseSink(CS_Sink sink, CS_Status* status);
@@ -404,7 +427,9 @@ void CS_ReleaseSink(CS_Sink sink, CS_Status* status);
* @defgroup cscore_mjpegserver_cfunc MjpegServer Sink Functions
* @{
*/
char* CS_GetMjpegServerListenAddress(CS_Sink sink, CS_Status* status);
void CS_GetMjpegServerListenAddress(CS_Sink sink,
struct WPI_String* listenAddress,
CS_Status* status);
int CS_GetMjpegServerPort(CS_Sink sink, CS_Status* status);
/** @} */
@@ -412,9 +437,9 @@ int CS_GetMjpegServerPort(CS_Sink sink, CS_Status* status);
* @defgroup cscore_frame_sink_cfunc Frame Sink Functions
* @{
*/
void CS_SetSinkDescription(CS_Sink sink, const char* description,
void CS_SetSinkDescription(CS_Sink sink, const struct WPI_String* description,
CS_Status* status);
char* CS_GetSinkError(CS_Sink sink, CS_Status* status);
void CS_GetSinkError(CS_Sink sink, struct WPI_String* error, CS_Status* status);
void CS_SetSinkEnabled(CS_Sink sink, CS_Bool enabled, CS_Status* status);
/** @} */
@@ -459,9 +484,10 @@ double CS_GetTelemetryAverageValue(CS_Handle handle, enum CS_TelemetryKind kind,
* @defgroup cscore_logging_cfunc Logging Functions
* @{
*/
typedef void (*CS_LogFunc)(unsigned int level, const char* file,
unsigned int line, const char* msg);
void CS_SetLogger(CS_LogFunc func, unsigned int min_level);
typedef void (*CS_LogFunc)(void* data, unsigned int level,
const struct WPI_String* file, unsigned int line,
const struct WPI_String* msg);
void CS_SetLogger(CS_LogFunc func, void* data, unsigned int min_level);
void CS_SetDefaultLogger(unsigned int min_level);
/** @} */
@@ -486,18 +512,14 @@ void CS_ReleaseEnumeratedSources(CS_Source* sources, int count);
CS_Sink* CS_EnumerateSinks(int* count, CS_Status* status);
void CS_ReleaseEnumeratedSinks(CS_Sink* sinks, int count);
void CS_FreeString(char* str);
void CS_FreeEnumPropertyChoices(char** choices, int count);
void CS_FreeUsbCameraInfo(CS_UsbCameraInfo* info);
void CS_FreeHttpCameraUrls(char** urls, int count);
void CS_FreeEnumeratedProperties(CS_Property* properties, int count);
void CS_FreeEnumeratedVideoModes(CS_VideoMode* modes, int count);
char* CS_GetHostname(void);
void CS_GetHostname(struct WPI_String* hostName);
char** CS_GetNetworkInterfaces(int* count);
void CS_FreeNetworkInterfaces(char** interfaces, int count);
struct WPI_String* CS_GetNetworkInterfaces(int* count);
/** @} */
/** @} */

View File

@@ -28,17 +28,17 @@ uint64_t CS_GrabRawSinkFrame(CS_Sink sink, struct WPI_RawFrame* rawImage,
uint64_t CS_GrabRawSinkFrameTimeout(CS_Sink sink, struct WPI_RawFrame* rawImage,
double timeout, CS_Status* status);
CS_Sink CS_CreateRawSink(const char* name, CS_Bool isCv, CS_Status* status);
CS_Sink CS_CreateRawSink(const struct WPI_String* name, CS_Bool isCv,
CS_Status* status);
CS_Sink CS_CreateRawSinkCallback(const char* name, CS_Bool isCv, void* data,
void (*processFrame)(void* data,
uint64_t time),
CS_Status* status);
CS_Sink CS_CreateRawSinkCallback(
const struct WPI_String* name, CS_Bool isCv, void* data,
void (*processFrame)(void* data, uint64_t time), CS_Status* status);
void CS_PutRawSourceFrame(CS_Source source, const struct WPI_RawFrame* image,
CS_Status* status);
CS_Source CS_CreateRawSource(const char* name, CS_Bool isCv,
CS_Source CS_CreateRawSource(const struct WPI_String* name, CS_Bool isCv,
const CS_VideoMode* mode, CS_Status* status);
/** @} */