Commit 3dd9d235 authored by François Heremans's avatar François Heremans
Browse files

Added MBSysC websocket module

parent c8483a4b
......@@ -6,12 +6,14 @@
* In order to use C++ features, you just need to change the extension of this file (.c) to .cc (or .cpp).
*/
#ifdef SDL
#include "realtime.h"
#include "events_sdl.h"
#include "user_realtime.h"
#ifdef SDL
/*! \brief handle inputs comming from the keyboard
*
* \param[in,out] mbs_data Robotran main structure
......@@ -92,3 +94,9 @@ void user_joystick_buttons(MbsData* mbs_data, int buttonID)
}
#endif
#ifdef WEBSOCKET
void user_keyboard(MbsData* mbs_data, Simu_realtime *realtime, int keyevent, int state){
}
#endif
\ No newline at end of file
......@@ -193,7 +193,7 @@ int main(int argc, char const *argv[])
mbs_dirdyn->options->dt0 = 1e-3;
mbs_dirdyn->options->tf = 10.0;
mbs_dirdyn->options->save2file = 1;
//mbs_dirdyn->options->realtime = 1;
mbs_dirdyn->options->realtime = 1;
mbs_run_dirdyn(mbs_dirdyn, mbs_data);
......
......@@ -75,6 +75,9 @@ function(mbsysc_specific_flags) # flag for lib_mbsysC only (not set by project)
# enable frame capture to record screenshot of the simulation
cmake_dependent_option(FLAG_FRAME_CAPTURE "Enable frame capture (need OpenGL)" OFF "FLAG_OPEN_GL" OFF)
# use the websocket to display in real-time the animation
cmake_dependent_option(FLAG_WEBSOCKET "Enable web 3D visualization" ON "FLAG_VISU" OFF)
endfunction()
## -- Static, dynamic libraries -- ##
......@@ -106,12 +109,14 @@ function(flags_check)
set( FLAG_VISU OFF )
set( FLAG_JAVA OFF )
set( FLAG_OPEN_GL OFF )
set( FLAG_WEBSOCKET OFF )
endif( )
# 3D visu
if (NOT FLAG_VISU)
set( FLAG_JAVA OFF )
set( FLAG_OPEN_GL OFF )
set( FLAG_WEBSOCKET OFF )
endif( )
# OpenGL only if no Java
......@@ -165,6 +170,7 @@ function(flags_check)
set( FLAG_VISU ${FLAG_VISU} PARENT_SCOPE )
set( FLAG_JAVA ${FLAG_JAVA} PARENT_SCOPE )
set( FLAG_OPEN_GL ${FLAG_OPEN_GL} PARENT_SCOPE )
set( FLAG_WEBSOCKET ${FLAG_WEBSOCKET} PARENT_SCOPE )
set( FLAG_SHARED_LIB ${FLAG_SHARED_LIB} PARENT_SCOPE )
set( FLAG_SEPARATE_BUILD ${FLAG_SEPARATE_BUILD} PARENT_SCOPE )
set( FLAG_SEPARATE_SYMBOLIC ${FLAG_SEPARATE_SYMBOLIC} PARENT_SCOPE )
......@@ -195,6 +201,7 @@ function(flags_clean)
unset(FLAG_VISU CACHE)
unset(FLAG_JAVA CACHE)
unset(FLAG_OPEN_GL CACHE)
unset(FLAG_WEBSOCKET CACHE)
unset(JNI_INCLUDE_JNI CACHE)
unset(JNI_INCLUDE_JNI_MD CACHE)
unset(SDL2_LIBRARIES_SDL2 CACHE)
......@@ -267,5 +274,9 @@ function(definitions)
set(LIB_MBSYSC_DEFINITIONS ${LIB_MBSYSC_DEFINITIONS} -DFRAME_CAPTURE)
endif( )
if(FLAG_WEBSOCKET)
add_definitions( -DWEBSOCKET )
endif( )
set(LIB_MBSYSC_DEFINITIONS ${LIB_MBSYSC_DEFINITIONS} PARENT_SCOPE)
endfunction()
......@@ -133,6 +133,14 @@ if (FLAG_REAL_TIME AND FLAG_OPEN_GL)
include_directories ("${PROJECT_BINARY_DIR}/conf")
endif ()
# Websocket files
if (FLAG_WEBSOCKET)
include_directories("./websocket")
increment_src( ${PROJECT_SOURCE_DIR}/websocket )
add_definitions( -DWEBSOCKET )
include_directories ("${PROJECT_BINARY_DIR}/conf")
endif ()
# list include directories (to find headers)
init_include()
set(INCLUDE_DIR ${INCLUDE_DIR} ${PROJECT_SOURCE_DIR}/realtime PARENT_SCOPE)
......@@ -178,8 +186,8 @@ set(LIB_MBSYSC_REALTIME_PATH ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE)
# include directories
include_directories("./")
include_directories("./sdl" "./sdl/auto_plot")
include_directories("./realtime")
include_directories("./sdl")
include_directories("./realtime" "./realtime/auto_plot")
include_directories("../mbs_struct")
include_directories("../mbs_utilities")
include_directories("../mbs_numerics")
......
#ifdef SDL
#include "auto_plot.h"
#include "useful_functions.h"
......@@ -106,4 +105,4 @@ int index_plot_string(AutoPlot *auto_plot, const char* label)
return -1;
}
#endif
......@@ -4,7 +4,6 @@
* \brief functions used to automatically update the user curves plotted
*/
#ifdef SDL
#ifndef _AUTO_PLOT_H_
#define _AUTO_PLOT_H_
......@@ -30,5 +29,5 @@ void free_auto_plot(AutoPlot *auto_plot);
void update_auto_plot(AutoPlot *auto_plot, double value, const char* label);
int index_plot_string(AutoPlot *auto_plot, const char* label);
#endif
#endif
......@@ -3,10 +3,6 @@
#endif // !HAVE_M_PI
#include "set_plot.h"
#ifdef SDL
#include "auto_plot.h"
static AutoPlot *auto_plot; // static AutoPlot structure with all the current user plots information
......@@ -21,10 +17,13 @@ void reset_flag_plot()
flag_plot = 0;
}
/*! \brief initialize the static auto_plot structure
*
* \param[in,out] screen_sdl SDL gestion main structure
*/
#ifdef SDL
void init_set_plot(Screen_sdl *screen_sdl)
{
flag_plot = 1;
......@@ -33,6 +32,17 @@ void init_set_plot(Screen_sdl *screen_sdl)
screen_sdl->auto_plot = auto_plot;
}
#else
void init_set_plot(Realtime_extern *realtime_ext, int max_nb_curves)
{
flag_plot = 1;
auto_plot = init_auto_plot(max_nb_curves);
realtime_ext->auto_plot = auto_plot;
}
#endif
/*! \brief release memory of auto_plot
*/
......@@ -56,5 +66,3 @@ void set_plot(double value, char* label)
update_auto_plot(auto_plot, value, label);
}
}
#endif
......@@ -11,9 +11,12 @@
#include "plot_sdl.h"
#ifdef SDL
void reset_flag_plot();
void init_set_plot(Screen_sdl *screen_sdl);
void free_set_plot();
#else
void init_set_plot(Realtime_extern *realtime_ext, int max_nb_curves);
#endif
void reset_flag_plot();
void free_set_plot();
#endif
......@@ -29,6 +29,11 @@
#include "open_gl_c_int.h"
#endif
#ifdef WEBSOCKET
#include "visu_websocket.h"
#include "auto_plot/set_plot.h"
#endif
// -- Macros -- //
#define USEC_TO_SEC 1.0e-6 //!< factor from us to s
......@@ -127,6 +132,13 @@ void mbs_realtime_update(Simu_realtime *realtime, double tsim)
update_past_visu(realtime, tsim);
}
#endif
#ifdef WEBSOCKET
if (realtime->flag_plot)
{
update_plot_vectors(realtime, tsim);
}
#endif
}
/*! \brief one loop iteration of the real-time process
......@@ -223,6 +235,8 @@ int mbs_realtime_loop(Simu_realtime *realtime, double tsim)
mbs_msg("\t >Real-time> Error: update open GL ! \n");
return err;
}
#elif (defined WEBSOCKET)
update_websocket(realtime);
#endif
}
}
......@@ -657,6 +671,11 @@ Simu_realtime* init_simu_realtime(MbsData* mbs_data, Realtime_option *options, i
return NULL;
}
}
#elif WEBSOCKET
{
init_set_plot(realtime->ext, 10);
// printf("\n Plot activated to websocket !\n");
}
#else
if (options->flag_plot)
{
......
......@@ -12,6 +12,7 @@
#include "realtime_ext.h"
#include "color_sdl.h"
#include "mbs_data.h"
#include "auto_plot/auto_plot.h"
#include "mbs_project_fct_ptr.h"
......@@ -33,6 +34,8 @@ typedef struct Realtime_extern
Realtime_visu *visu; //!< Java structure
#endif
AutoPlot *auto_plot; ///< automatic user plot update structure
MbsData* mbs_data; //!< Robotran main structure
} Realtime_extern;
......@@ -77,6 +80,7 @@ struct Realtime_option
int nb_models; //!< number of models to load
int *nb_q; //!< number of joints in the .mbs used for visualization (for each model)
char **mbs_file; //!< path and file name fot the .mbs file used for Java visualization (for each model)
char *project_path; //!< path for the project
int start_viewpoint; //!< initial visu viewpoint ID
......
......@@ -27,6 +27,10 @@
#include "open_gl_c_int.h"
#endif
#ifdef WEBSOCKET
#include "visu_websocket.h"
#endif
#ifdef SDL
/*! \brief initialize SDL real-time variables
......@@ -211,6 +215,8 @@ Realtime_visu* init_realtime_visu(void *realtime_options, MbsData* mbs_data, int
mbs_msg("\t >Real-time> Error [%d] :in init_open gl visu ! \n", *err);
return NULL;
}
#elif (defined WEBSOCKET)
init_websocket(visu, mbs_data, nb_models, nb_q, visu->cur_q, options->mbs_file, options->project_path, options->start_viewpoint);
#endif
*err = 0;
return visu;
......@@ -259,8 +265,9 @@ int free_realtime_visu(Realtime_visu *visu)
mbs_msg("\t >Real-time> Error: free open GL ! \n");
return err;
}
#elif (defined WEBSOCKET)
free_websocket(visu->visu_class);
#endif
free(visu);
return 0;
}
......
......@@ -25,6 +25,18 @@ extern "C" {
#endif
#endif
#ifdef WEBSOCKET
#ifdef __cplusplus
extern "C" {
#endif
void user_realtime_plot(MbsData* mbs_data);
void user_keyboard(MbsData* mbs_data, Simu_realtime *realtime, int keyevent, int state);
#ifdef __cplusplus
}
#endif
#endif
#endif
#ifdef __cplusplus
......
/*
Copyright (C) 2011 Joseph A. Adams (joeyadams3.14159@gmail.com)
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "json.h"
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define out_of_memory() do { \
fprintf(stderr, "Out of memory.\n"); \
exit(EXIT_FAILURE); \
} while (0)
/* Sadly, strdup is not portable. */
static char *json_strdup(const char *str)
{
char *ret = (char*) malloc(strlen(str) + 1);
if (ret == NULL)
out_of_memory();
strcpy(ret, str);
return ret;
}
/* String buffer */
typedef struct
{
char *cur;
char *end;
char *start;
} SB;
static void sb_init(SB *sb)
{
sb->start = (char*) malloc(17);
if (sb->start == NULL)
out_of_memory();
sb->cur = sb->start;
sb->end = sb->start + 16;
}
/* sb and need may be evaluated multiple times. */
#define sb_need(sb, need) do { \
if ((sb)->end - (sb)->cur < (need)) \
sb_grow(sb, need); \
} while (0)
static void sb_grow(SB *sb, int need)
{
size_t length = sb->cur - sb->start;
size_t alloc = sb->end - sb->start;
do {
alloc *= 2;
} while (alloc < length + need);
sb->start = (char*) realloc(sb->start, alloc + 1);
if (sb->start == NULL)
out_of_memory();
sb->cur = sb->start + length;
sb->end = sb->start + alloc;
}
static void sb_put(SB *sb, const char *bytes, int count)
{
sb_need(sb, count);
memcpy(sb->cur, bytes, count);
sb->cur += count;
}
#define sb_putc(sb, c) do { \
if ((sb)->cur >= (sb)->end) \
sb_grow(sb, 1); \
*(sb)->cur++ = (c); \
} while (0)
static void sb_puts(SB *sb, const char *str)
{
sb_put(sb, str, strlen(str));
}
static char *sb_finish(SB *sb)
{
*sb->cur = 0;
assert(sb->start <= sb->cur && strlen(sb->start) == (size_t)(sb->cur - sb->start));
return sb->start;
}
static void sb_free(SB *sb)
{
free(sb->start);
}
/*
* Unicode helper functions
*
* These are taken from the ccan/charset module and customized a bit.
* Putting them here means the compiler can (choose to) inline them,
* and it keeps ccan/json from having a dependency.
*/
/*
* Type for Unicode codepoints.
* We need our own because wchar_t might be 16 bits.
*/
typedef uint32_t uchar_t;
/*
* Validate a single UTF-8 character starting at @s.
* The string must be null-terminated.
*
* If it's valid, return its length (1 thru 4).
* If it's invalid or clipped, return 0.
*
* This function implements the syntax given in RFC3629, which is
* the same as that given in The Unicode Standard, Version 6.0.
*
* It has the following properties:
*
* * All codepoints U+0000..U+10FFFF may be encoded,
* except for U+D800..U+DFFF, which are reserved
* for UTF-16 surrogate pair encoding.
* * UTF-8 byte sequences longer than 4 bytes are not permitted,
* as they exceed the range of Unicode.
* * The sixty-six Unicode "non-characters" are permitted
* (namely, U+FDD0..U+FDEF, U+xxFFFE, and U+xxFFFF).
*/
static int utf8_validate_cz(const char *s)
{
unsigned char c = *s++;
if (c <= 0x7F) { /* 00..7F */
return 1;
} else if (c <= 0xC1) { /* 80..C1 */
/* Disallow overlong 2-byte sequence. */
return 0;
} else if (c <= 0xDF) { /* C2..DF */
/* Make sure subsequent byte is in the range 0x80..0xBF. */
if (((unsigned char)*s++ & 0xC0) != 0x80)
return 0;
return 2;
} else if (c <= 0xEF) { /* E0..EF */
/* Disallow overlong 3-byte sequence. */
if (c == 0xE0 && (unsigned char)*s < 0xA0)
return 0;
/* Disallow U+D800..U+DFFF. */
if (c == 0xED && (unsigned char)*s > 0x9F)
return 0;
/* Make sure subsequent bytes are in the range 0x80..0xBF. */
if (((unsigned char)*s++ & 0xC0) != 0x80)
return 0;
if (((unsigned char)*s++ & 0xC0) != 0x80)
return 0;
return 3;
} else if (c <= 0xF4) { /* F0..F4 */
/* Disallow overlong 4-byte sequence. */
if (c == 0xF0 && (unsigned char)*s < 0x90)
return 0;
/* Disallow codepoints beyond U+10FFFF. */
if (c == 0xF4 && (unsigned char)*s > 0x8F)
return 0;
/* Make sure subsequent bytes are in the range 0x80..0xBF. */
if (((unsigned char)*s++ & 0xC0) != 0x80)
return 0;
if (((unsigned char)*s++ & 0xC0) != 0x80)
return 0;
if (((unsigned char)*s++ & 0xC0) != 0x80)
return 0;
return 4;
} else { /* F5..FF */
return 0;
}
}
/* Validate a null-terminated UTF-8 string. */
static bool utf8_validate(const char *s)
{
int len;
for (; *s != 0; s += len) {
len = utf8_validate_cz(s);
if (len == 0)
return false;
}
return true;
}
/*
* Read a single UTF-8 character starting at @s,
* returning the length, in bytes, of the character read.
*
* This function assumes input is valid UTF-8,
* and that there are enough characters in front of @s.
*/
static int utf8_read_char(const char *s, uchar_t *out)
{
const unsigned char *c = (const unsigned char*) s;
assert(utf8_validate_cz(s));
if (c[0] <= 0x7F) {
/* 00..7F */
*out = c[0];
return 1;
} else if (c[0] <= 0xDF) {
/* C2..DF (unless input is invalid) */
*out = ((uchar_t)c[0] & 0x1F) << 6 |
((uchar_t)c[1] & 0x3F);
return 2;
} else if (c[0] <= 0xEF) {
/* E0..EF */
*out = ((uchar_t)c[0] & 0xF) << 12 |
((uchar_t)c[1] & 0x3F) << 6 |
((uchar_t)c[2] & 0x3F);
return 3;
} else {
/* F0..F4 (unless input is invalid) */
*out = ((uchar_t)c[0] & 0x7) << 18 |
((uchar_t)c[1] & 0x3F) << 12 |
((uchar_t)c[2] & 0x3F) << 6 |
((uchar_t)c[3] & 0x3F);
return 4;
}
}
/*
* Write a single UTF-8 character to @s,
* returning the length, in bytes, of the character written.
*
* @unicode must be U+0000..U+10FFFF, but not U+D800..U+DFFF.
*
* This function will write up to 4 bytes to @out.
*/
static int utf8_write_char(uchar_t unicode, char *out)
{
unsigned char *o = (unsigned char*) out;
assert(unicode <= 0x10FFFF && !(unicode >= 0xD800 && unicode <= 0xDFFF));
if (unicode <= 0x7F) {
/* U+0000..U+007F */
*o++ = unicode;
return 1;
} else if (unicode <= 0x7FF) {
/* U+0080..U+07FF */
*o++ = 0xC0 | unicode >> 6;
*o++ = 0x80 | (unicode & 0x3F);
return 2;
} else if (unicode <= 0xFFFF) {
/* U+0800..U+FFFF */
*o++ = 0xE0 | unicode >> 12;
*o++ = 0x80 | (unicode >> 6 & 0x3F);
*o++ = 0x80 | (unicode & 0x3F);
return 3;
} else {
/* U+10000..U+10FFFF */
*o++ = 0xF0 | unicode >> 18;
*o++ = 0x80 | (unicode >> 12 & 0x3F);
*o++ = 0x80 | (unicode >> 6 & 0x3F);
*o++ = 0x80 | (unicode & 0x3F);