Skip to content

Commit

Permalink
Add FileSystem path "combine" method.
Browse files Browse the repository at this point in the history
Move log files to a dated folder.
Fix crashes in getImageForCamera.
Add ability to get series of images using DroneShell.
  • Loading branch information
lovettchris committed Mar 4, 2017
1 parent d006d53 commit f6c45e0
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 64 deletions.
1 change: 1 addition & 0 deletions AirLib/AirLib.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<ClInclude Include="include\common\common_utils\ctpl_stl.h" />
<ClInclude Include="include\common\common_utils\EnumFlags.hpp" />
<ClInclude Include="include\common\common_utils\ExceptionUtils.hpp" />
<ClInclude Include="include\common\common_utils\FileSystem.hpp" />
<ClInclude Include="include\common\common_utils\json.hpp" />
<ClInclude Include="include\common\common_utils\MedianFilter.hpp" />
<ClInclude Include="include\common\common_utils\OnlineStats.hpp" />
Expand Down
6 changes: 6 additions & 0 deletions AirLib/AirLib.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,9 @@
<ClInclude Include="include\controllers\Settings.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\common\common_utils\FileSystem.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\controllers\DroneControllerBase.cpp">
Expand All @@ -272,5 +275,8 @@
<ClCompile Include="src\rpc\RpcLibServer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\controllers\FileSystem.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
43 changes: 32 additions & 11 deletions AirLib/include/common/common_utils/FileSystem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@ namespace common_utils {
class FileSystem
{
typedef unsigned int uint;
public:

// please use the combine() method instead.
static const char kPathSeparator =
#ifdef _WIN32
'\\';
#else
'/';
#endif
#ifdef _WIN32
'\\';
#else
'/';
#endif

static std::string createDirectory(std::string parentFolder, std::string name);
public:

static std::string createDirectory(std::string fullPath);

static std::string getUserHomeFolder()
{
Expand All @@ -44,10 +46,27 @@ class FileSystem

static std::string getUserDocumentsFolder();

static std::string ensureAppDataFolder() {
std::string docs = getUserDocumentsFolder();
static std::string getAppDataFolder() {
return ensureFolder(combine(getUserDocumentsFolder(), ProductFolderName));
}

static std::string ensureFolder(std::string fullpath) {
// make sure this directory exists.
return createDirectory(docs, ProductFolderName);
return createDirectory(fullpath);
}

static std::string combine(const std::string parentFolder, const std::string child) {
size_t len = parentFolder.size();
if (len > 0 && parentFolder[len - 1] == kPathSeparator) {
// parent already ends with '/'
return parentFolder + child;
}
len = child.size();
if (len > 0 && child[0] == kPathSeparator) {
// child already starts with '/'
return parentFolder + child;
}
return parentFolder + kPathSeparator + child;
}

static std::string getFileExtension(const std::string str)
Expand All @@ -68,9 +87,11 @@ class FileSystem

static std::string getLogFileNamePath(std::string prefix, std::string suffix, std::string extension, bool add_timestamp)
{
std::string logfolder = Utils::to_string(Utils::now(), "%Y-%m-%d");
std::string fullPath = combine(getAppDataFolder(), logfolder);
std::string timestamp = add_timestamp ? Utils::to_string(Utils::now()) : "";
std::stringstream filename_ss;
filename_ss << ensureAppDataFolder() << kPathSeparator << prefix << suffix << timestamp << extension;
filename_ss << ensureFolder(fullPath) << kPathSeparator << prefix << suffix << timestamp << extension;
return filename_ss.str();
}

Expand Down
7 changes: 1 addition & 6 deletions AirLib/include/common/common_utils/Utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,12 +375,7 @@ class Utils {

static string to_string(time_point<system_clock> time)
{
time_t tt = system_clock::to_time_t(time);

char str[1024];
if (std::strftime(str, sizeof(str), "%Y-%m-%d-%H-%M-%S", std::localtime(&tt)))
return string(str);
else return string();
return to_string(now(), "%Y-%m-%d-%H-%M-%S");

/* GCC doesn't implement put_time yet
stringstream ss;
Expand Down
4 changes: 2 additions & 2 deletions AirLib/include/controllers/Settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ namespace msr {

static std::string getFullPath(std::string fileName)
{
std::string path = common_utils::FileSystem::ensureAppDataFolder();
return path + common_utils::FileSystem::kPathSeparator + fileName;
std::string path = common_utils::FileSystem::getAppDataFolder();
return common_utils::FileSystem::combine(path, fileName);
}

static Settings& loadJSonFile(std::string fileName)
Expand Down
14 changes: 11 additions & 3 deletions AirLib/src/controllers/DroneControllerBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -670,17 +670,25 @@ vector<uint8_t> DroneControllerBase::getImageForCamera(int camera_id, ImageType
//TODO: bug: MSGPACK bombs out if vector if of 0 size
static vector<uint8_t> empty_vec(1);

vector<uint8_t> result;

//TODO: perf work
auto it = images.find(camera_id);
if (it != images.end()) {
auto it2 = it->second.find(type);
if (it2 != it->second.end())
return it2->second;
result = it2->second;
else
return empty_vec;
result = empty_vec;

} else
return empty_vec;
result = empty_vec;

if (result.size() == 0) {
result = empty_vec;
}

return result;
}

}} //namespace
Expand Down
27 changes: 13 additions & 14 deletions AirLib/src/controllers/FileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include <Shlobj.h>
#include <direct.h>
#include <stdlib.h>
#include <stdio.h>
#include <direct.h>
#else
#include <unistd.h>
#include <sys/param.h> // MAXPATHLEN definition
Expand All @@ -24,21 +24,22 @@ using namespace common_utils;

// File names are unicode (std::wstring), because users can create folders containing unicode characters on both
// Windows, OSX and Linux.
std::string FileSystem::createDirectory(std::string parentFolder, std::string name) {
std::string path = parentFolder + kPathSeparator + name;
std::string FileSystem::createDirectory(std::string fullPath) {

#ifdef _WIN32

std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
std::wstring wide_parent = converter.from_bytes(parentFolder);
std::wstring wide_name = converter.from_bytes(name);
int hr = CreateDirectoryEx(wide_parent.c_str(), wide_name.c_str(), NULL);
if (hr != 0) {
common_utils::Utils::logMessage("CreateDirectoryEx failed %d\n", GetLastError());
std::wstring wide_path = converter.from_bytes(fullPath);
int hr = CreateDirectory(wide_path.c_str(), NULL);
if (hr == 0) {
hr = GetLastError();
if (hr != ERROR_ALREADY_EXISTS) {
throw std::invalid_argument(Utils::stringf("Error creating directory, hr=%d", hr));
}
}
#else
mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
mkdir(fullPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#endif
return path;
return fullPath;
}


Expand All @@ -59,10 +60,8 @@ std::string FileSystem::getUserDocumentsFolder() {
}

// fall back in case SHGetFolderPath failed for some reason.
return getUserHomeFolder() + kPathSeparator + "Documents";
#else
return getUserHomeFolder() + kPathSeparator + "Documents";
#endif
return combine(getUserHomeFolder(), "Documents");
}

#endif
63 changes: 43 additions & 20 deletions DroneShell/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -936,17 +936,57 @@ See RecordPose for information about log file format")


class GetImageCommand : public DroneCommand {
int image_index_ = 0;
public:
GetImageCommand() : DroneCommand("GetImage", "Get an image from the simulator")
{
this->addSwitch({"-type", "depth", "scene, depth, or segmentation" });
this->addSwitch({"-name", "image", "name of the file" });
this->addSwitch({ "-type", "depth", "scene, depth, or segmentation" });
this->addSwitch({ "-name", "image", "name of the file" });
this->addSwitch({ "-iterations", "1", "number of images to capture" });
this->addSwitch({ "-pause_time", "100", "pause time between each image in milliseconds (default 100)" });
}

void getImages(CommandContext* context, DroneControllerBase::ImageType imageType, std::string baseName, int iterations, int pause_time)
{
// group the images by the current date.
std::string folderName = Utils::to_string(Utils::now(), "%Y-%m-%d");
std::string path = FileSystem::ensureFolder(FileSystem::combine(FileSystem::getAppDataFolder(), folderName));

for (int i = 0; i < iterations; i++) {

context->client.setImageTypeForCamera(0, imageType);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // give it time to generate image.
auto image = context->client.getImageForCamera(0, imageType);
// turn it off again so simulator doesn't choke...
context->client.setImageTypeForCamera(0, DroneControllerBase::ImageType::None);

// size 1 is a trick we had to do to keep RPCLIB happy...
if (image.size() <= 1) {
cout << "error getting image, check sim for error messages" << endl;
return;
}

std::string imageName = Utils::stringf("%s%d.png", baseName.c_str(), image_index_++);
std::string file_path_name = FileSystem::combine(path, imageName);

ofstream file;
FileSystem::createBinaryFile(file_path_name, file);
file.write(reinterpret_cast<const char*>(image.data()), image.size());
file.close();

cout << "Image saved to: " << file_path_name << " (" << image.size() << " bytes)" << endl;

std::this_thread::sleep_for(std::chrono::milliseconds(pause_time));
}

}

bool execute(const DroneCommandParameters& params)
{
std::string type = getSwitch("-type").value;
std::string name = getSwitch("-name").value;
int iterations = std::stoi(getSwitch("-iterations").value);
int pause_time = std::stoi(getSwitch("-pause_time").value);
CommandContext* context = params.context;

DroneControllerBase::ImageType imageType;
Expand All @@ -963,24 +1003,7 @@ class GetImageCommand : public DroneCommand {
}

context->tasker.execute([=]() {
std::string file_path_name = FileSystem::getLogFileNamePath(name, "", ".png", false);

context->client.setImageTypeForCamera(0, imageType);

auto image = context->client.getImageForCamera(0, imageType);

// if we are too quick we miss the image.
while (image.size() <= 1) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
image = context->client.getImageForCamera(0, imageType);
}
ofstream file;
FileSystem::createBinaryFile(file_path_name, file);
file.write(reinterpret_cast<const char*>(image.data()), image.size());
file.close();

cout << "Image saved to: " << name << " (" << image.size() << " bytes)" << endl;

getImages(context, imageType, name, iterations, pause_time);
});

return false;
Expand Down
7 changes: 0 additions & 7 deletions MavLinkCom/common_utils/Utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,6 @@ class Utils {
using time_point = std::chrono::time_point<T>;

public:
static const char kPathSeparator =
#ifdef _WIN32
'\\';
#else
'/';
#endif

static void enableImmediateConsoleFlush() {
//disable buffering
setbuf(stdout, NULL);
Expand Down
8 changes: 7 additions & 1 deletion Unreal/Plugins/AirSim/Source/PIPCamera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,18 @@ bool APIPCamera::getScreenshot(EPIPCameraType camera_type, TArray<uint8>& compre
{
USceneCaptureComponent2D* capture = getCaptureComponent(camera_type, true);;


if (capture == nullptr) {
UAirBlueprintLib::LogMessage(TEXT("Can't take screenshot because eithercamera type is not active"), TEXT(""), LogDebugLevel::Failure);
return false;
}

capture->TextureTarget = getTexureRenderTarget(camera_type, false);

if (capture->TextureTarget == nullptr) {
UAirBlueprintLib::LogMessage(TEXT("Can't take screenshot because texture target is null"), TEXT(""), LogDebugLevel::Failure);
return false;
}

FTextureRenderTargetResource* resource = capture->TextureTarget->GameThread_GetRenderTargetResource();

if (resource == nullptr) {
Expand Down

0 comments on commit f6c45e0

Please sign in to comment.