Pull request for the Extensions interface only (#655)

* Modify halsim to be able to load extension libraries if they are available.

It will read the list of libraries to try from the HALSIM_EXTENSIONS
environment variable.  Multiple libraries can be given if separated
by ';' (Windows) or ':' (Unix).

The library must have an 'HALSIM_InitExtension' method that returns >= 0 on success.

The library is expected to use the interface expressed by
  hal/src/src/main/native/include/MockData

* Add a simple halsim library that just prints robot values.

This makes a good test bed for cross platform purposes,
and provides the ultimate in light weight simulators.

This initial version only prints PWM values.
This commit is contained in:
Jeremy White
2017-10-18 02:27:55 -05:00
committed by Peter Johnson
parent 2fc60680f4
commit be77f9cb26
11 changed files with 284 additions and 0 deletions

View File

@@ -108,6 +108,11 @@ model {
}
}
}
binaries.all { binary ->
if (binary.targetPlatform.operatingSystem.linux) {
linker.args "-ldl"
}
}
}
if (project.hasProperty('buildHalStaticDeps')) {
halSimStaticDeps(NativeLibrarySpec) {

View File

@@ -0,0 +1,25 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
/**
* HAL Simulator Extensions are libraries that provide additional simulator
* functionality, such as a Gazebo interface, or a more light weight simulation.
*
* An extension must expose the HALSIM_InitExtension entry point which is
* invoked after the library is loaded.
*
* The entry point is expected to return < 0 for errors that should stop
* the HAL completely, 0 for success, and > 0 for a non fatal error.
*/
typedef int halsim_extension_init_func_t(void);
extern "C" {
int HAL_LoadOneExtension(const char* library);
int HAL_LoadExtensions(void);
}

View File

@@ -0,0 +1,83 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "HAL/Extensions.h"
#include <llvm/SmallString.h>
#include <llvm/StringRef.h>
#include "HAL/HAL.h"
#if defined(WIN32) || defined(_WIN32)
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#if defined(WIN32) || defined(_WIN32)
#define DELIM ';'
#define HTYPE HMODULE
#define DLOPEN(a) LoadLibrary(a)
#define DLSYM GetProcAddress
#define DLCLOSE FreeLibrary
#else
#define DELIM ':'
#define HTYPE void*
#define PREFIX "lib"
#define DLOPEN(a) dlopen(a, RTLD_LAZY)
#define DLSYM dlsym
#define DLCLOSE dlclose
#endif
extern "C" {
int HAL_LoadOneExtension(const char* library) {
int rc = 1; // It is expected and reasonable not to find an extra simulation
HTYPE handle = DLOPEN(library);
#if !defined(WIN32) && !defined(_WIN32)
if (!handle) {
llvm::SmallString<128> libraryName("lib");
libraryName += library;
#if defined(__APPLE__)
libraryName += ".dylib";
#else
libraryName += ".so";
#endif
handle = DLOPEN(libraryName.c_str());
}
#endif
if (!handle) return rc;
auto init = reinterpret_cast<halsim_extension_init_func_t*>(
DLSYM(handle, "HALSIM_InitExtension"));
if (init) rc = (*init)();
if (rc != 0) DLCLOSE(handle);
return rc;
}
/**
* Load any extra halsim libraries provided in the HALSIM_EXTENSIONS
* environment variable.
*/
int HAL_LoadExtensions(void) {
int rc = 1;
llvm::SmallVector<llvm::StringRef, 2> libraries;
const char* e = std::getenv("HALSIM_EXTENSIONS");
if (!e) return rc;
llvm::StringRef env{e};
env.split(libraries, DELIM, -1, false);
for (auto& libref : libraries) {
llvm::SmallString<128> library(libref);
rc = HAL_LoadOneExtension(library.c_str());
if (rc < 0) break;
}
return rc;
}
} // extern "C"

View File

@@ -10,6 +10,7 @@
#include "ErrorsInternal.h"
#include "HAL/DriverStation.h"
#include "HAL/Errors.h"
#include "HAL/Extensions.h"
#include "HAL/handles/HandlesInternal.h"
#include "MockData/RoboRioDataInternal.h"
#include "MockHooksInternal.h"
@@ -203,6 +204,7 @@ HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {
// Second check in case another thread was waiting
if (initialized) return true;
if (HAL_LoadExtensions() < 0) return false;
hal::RestartTiming();
HAL_InitializeDriverStation();

View File

@@ -8,3 +8,4 @@ include 'wpilibj'
include 'wpilibjIntegrationTests'
include 'wpilibjExamples'
include 'myRobot'
include 'simulation:halsim_print'

View File

@@ -0,0 +1,26 @@
description = "A simulation shared object that simply prints robot behaviors"
apply plugin: 'edu.wpi.first.NativeUtils'
apply plugin: 'cpp'
ext.skipAthena = true
apply from: "../../config.gradle"
model {
components {
halsim_print(NativeLibrarySpec)
}
binaries {
all {
project(':hal').addHalCompilerArguments(it)
project(':hal').addHalToLinker(it)
}
withType(StaticLibraryBinarySpec) {
it.buildable = false
}
}
}
apply from: 'publish.gradle'

View File

@@ -0,0 +1,43 @@
apply plugin: 'maven-publish'
apply plugin: 'edu.wpi.first.wpilib.versioning.WPILibVersioningPlugin'
if (!hasProperty('releaseType')) {
WPILibVersion {
releaseType = 'dev'
}
}
def pubVersion = ''
if (project.hasProperty("publishVersion")) {
pubVersion = project.publishVersion
} else {
pubVersion = WPILibVersion.version
}
def baseArtifactId = 'halsim-print'
def artifactGroupId = 'edu.wpi.first.halsim'
model {
publishing {
def libSpec
$.components.each {
if (it in NativeLibrarySpec) {
$.binaries.each {
if (it in SharedLibraryBinarySpec) {
libSpec = it.sharedLibraryFile
}
}
}
}
publications {
cpp(MavenPublication) {
artifact libSpec
artifactId = baseArtifactId
groupId artifactGroupId
version pubVersion
}
}
}
}

View File

@@ -0,0 +1,29 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "PrintPWM.h"
#include <iostream>
#include "MockData/HAL_Value.h"
#include "MockData/NotifyListener.h"
#include "MockData/PWMData.h"
static void PWMCallback(const char* name, void* param,
const struct HAL_Value* value) {
auto pwm = static_cast<PrintPWM*>(param);
pwm->Publish(value->data.v_double);
}
PrintPWM::PrintPWM(int port) {
m_port = port;
HALSIM_RegisterPWMSpeedCallback(port, PWMCallback, this, false);
}
void PrintPWM::Publish(double value) {
std::cout << "PWM " << m_port << ": " << value << std::endl;
}

View File

@@ -0,0 +1,34 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include <iostream>
#include <HAL/Ports.h>
#include "HALSimPrint.h"
#include "PrintPWM.h"
/**
* Currently, robots never terminate, so we keep a single static object
* and it is never properly released or cleaned up.
*/
static HALSimPrint halsim;
extern "C" {
#if defined(WIN32) || defined(_WIN32)
__declspec(dllexport)
#endif
int HALSIM_InitExtension(void) {
std::cout << "Print Simulator Initializing." << std::endl;
int pwmCount = HAL_GetNumPWMChannels();
halsim.m_pwms.reserve(pwmCount);
for (int i = 0; i < pwmCount; i++) halsim.m_pwms.emplace_back(i);
return 0;
}
} // extern "C"

View File

@@ -0,0 +1,17 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <vector>
class PrintPWM;
class HALSimPrint {
public:
std::vector<PrintPWM> m_pwms;
};

View File

@@ -0,0 +1,19 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "HALSimPrint.h"
class PrintPWM {
public:
explicit PrintPWM(int port);
void Publish(double value);
private:
int m_port;
};