Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
A
advLigoRTS
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Deploy
Releases
Container Registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
CDS
software
advLigoRTS
Commits
8fd405ce
Commit
8fd405ce
authored
5 years ago
by
Jonathan Hanks
Browse files
Options
Downloads
Patches
Plain Diff
WIP adding http diagnostics to the standalone_edc.
This allows disconnected channel lists to be extracted from the edc.
parent
b49b55e9
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
CMakeLists.txt
+2
-0
2 additions, 0 deletions
CMakeLists.txt
src/epics/seq/CMakeLists.txt
+13
-3
13 additions, 3 deletions
src/epics/seq/CMakeLists.txt
src/epics/seq/standalone_edcu.cc
+360
-2
360 additions, 2 deletions
src/epics/seq/standalone_edcu.cc
with
375 additions
and
5 deletions
CMakeLists.txt
+
2
−
0
View file @
8fd405ce
...
...
@@ -26,6 +26,8 @@ FIND_PACKAGE(OpenMX)
FIND_PACKAGE
(
ZMQ4
)
FIND_PACKAGE
(
Dolphin
)
FIND_PACKAGE
(
NDS2Client
)
FIND_PACKAGE
(
Boost COMPONENTS system
)
FIND_PACKAGE
(
RapidJSON
)
CHECK_CXX_SOURCE_COMPILES
(
"#include <iostream>
#include <FlexLexer.h>
...
...
This diff is collapsed.
Click to expand it.
src/epics/seq/CMakeLists.txt
+
13
−
3
View file @
8fd405ce
if
(
Boost_FOUND
)
add_executable
(
standalone_edc
standalone_edcu.cc
${
CMAKE_CURRENT_SOURCE_DIR
}
/../../drv/rfm.c
)
target_include_directories
(
standalone_edc PUBLIC
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/../../include"
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/../../include/drv"
)
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/../../include/drv"
${
Boost_INCLUDE_DIRS
}
)
target_link_libraries
(
standalone_edc PUBLIC
epics::ca
driver::ini_parsing
)
driver::ini_parsing
${
Boost_LIBRARIES
}
${
CMAKE_THREAD_LIBS_INIT
}
)
target_requires_cpp11
(
standalone_edc PUBLIC
)
install
(
TARGETS standalone_edc DESTINATION bin
)
install
(
TARGETS standalone_edc DESTINATION bin
)
\ No newline at end of file
else
(
Boost_FOUND
)
message
(
WARNING
"The standalone_edc will not be build as boost was not found"
)
endif
(
Boost_FOUND
)
\ No newline at end of file
This diff is collapsed.
Click to expand it.
src/epics/seq/standalone_edcu.cc
+
360
−
2
View file @
8fd405ce
...
...
@@ -14,6 +14,12 @@ of this distribution.
// - Make appropriate log file entries
// - Get rid of need to build skeleton.st
#include
<algorithm>
#include
<iterator>
#include
<string>
#include
<thread>
#include
<utility>
#include
<stddef.h>
#include
<stdlib.h>
#include
<string.h>
...
...
@@ -28,6 +34,14 @@ of this distribution.
#include
<daqmap.h>
#define BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM
#include
<boost/asio.hpp>
#include
<boost/date_time/posix_time/posix_time.hpp>
#include
<boost/lockfree/spsc_queue.hpp>
#include
<rapidjson/writer.h>
#include
<rapidjson/stringbuffer.h>
/* taken from channel.h in the daqd source
* find a way to do this better
*/
...
...
@@ -57,6 +71,38 @@ extern "C" {
#include
<iostream>
#define EDCU_MAX_CHANS 50000
#define DIAG_QUEUE_DEPTH 3
using
boost
::
asio
::
ip
::
tcp
;
#if BOOST_ASIO_VERSION < 101200
using
io_context_t
=
boost
::
asio
::
io_service
;
inline
io_context_t
&
get_context
(
tcp
::
acceptor
&
acceptor
)
{
return
acceptor
.
get_io_service
(
);
}
inline
boost
::
asio
::
ip
::
address
make_address
(
const
char
*
str
)
{
return
boost
::
asio
::
ip
::
address
::
from_string
(
str
);
}
#else
using
io_context_t
=
boost
::
asio
::
io_context
;
inline
io_context_t
&
get_context
(
tcp
::
acceptor
&
acceptor
)
{
return
acceptor
.
get_executor
(
).
context
(
);
}
inline
boost
::
asio
::
ip
::
address
make_address
(
const
char
*
str
)
{
return
boost
::
asio
::
ip
::
make_address
(
str
);
}
#endif
// Function prototypes
// ****************************************************************************************
...
...
@@ -111,6 +157,97 @@ int timemarks[ 16 ] = { 1000 * 1000, 63500 * 1000, 126000 * 1000,
938500
*
1000
};
int
nextTrig
=
0
;
/*!
* @brief A collection of information used for diagnostic output
*/
struct
diag_info_block
{
diag_info_block
(
)
:
con_chans
(
0
),
status
(
)
{
std
::
fill
(
std
::
begin
(
status
),
std
::
end
(
status
),
0xbad
);
}
diag_info_block
(
const
diag_info_block
&
other
)
:
con_chans
(
other
.
con_chans
),
status
(
)
{
std
::
copy
(
std
::
begin
(
other
.
status
),
std
::
end
(
other
.
status
),
std
::
begin
(
status
)
);
}
diag_info_block
&
operator
=
(
const
diag_info_block
&
other
)
{
con_chans
=
other
.
con_chans
;
std
::
copy
(
std
::
begin
(
other
.
status
),
std
::
end
(
other
.
status
),
std
::
begin
(
status
)
);
return
*
this
;
}
int
con_chans
;
int
status
[
EDCU_MAX_CHANS
];
};
typedef
boost
::
lockfree
::
spsc_queue
<
diag_info_block
*
,
boost
::
lockfree
::
capacity
<
DIAG_QUEUE_DEPTH
>
>
diag_queue_t
;
/*!
* @brief this structure is used to refer to the message queues used between the
* main thread and the diag thread.
*/
struct
diag_thread_queues
{
diag_thread_queues
(
diag_queue_t
&
message_queue
,
diag_queue_t
&
free_list_queue
)
:
msg_queue
(
message_queue
),
free_queue
(
free_list_queue
)
{
}
diag_queue_t
&
msg_queue
;
diag_queue_t
&
free_queue
;
};
/*!
* @brief this structure is used to give the diag thread the information it
* needs to start and run.
*/
struct
diag_thread_args
{
diag_thread_args
(
const
std
::
string
&
hostname
,
int
port
,
diag_queue_t
&
message_queue
,
diag_queue_t
&
free_list_queue
)
:
address
(
hostname
,
port
),
queues
(
message_queue
,
free_list_queue
)
{
}
diag_thread_args
(
diag_queue_t
&
message_queue
,
diag_queue_t
&
free_list_queue
)
:
address
(
"127.0.0.1"
,
9000
),
queues
(
message_queue
,
free_list_queue
)
{
}
std
::
pair
<
std
::
string
,
int
>
address
;
diag_thread_queues
queues
;
};
struct
diag_client_conn
{
diag_client_conn
(
io_context_t
&
io
)
:
io_context
(
io
),
socket
(
io
),
data
(
),
buffer
(
)
{
}
io_context_t
&
io_context
;
tcp
::
socket
socket
;
diag_info_block
data
;
std
::
string
buffer
;
};
// forward
void
diag_thread_mainloop
(
diag_thread_args
*
args
);
void
update_diag_info
(
diag_thread_queues
&
queues
);
// End Header ************************************************************
//
...
...
@@ -431,6 +568,7 @@ channel_parse_callback( char* channel_name,
<<
static_cast
<
int
>
(
_32bit_integer
)
<<
")
\n
"
;
exit
(
1
);
}
edc
->
channel_type
[
edc
->
num_chans
]
=
daq_data_type
;
strncpy
(
edc
->
channel_name
[
edc
->
num_chans
],
channel_name
,
sizeof
(
edc
->
channel_name
[
edc
->
num_chans
]
)
);
...
...
@@ -688,12 +826,13 @@ usage( const char* prog )
std
::
cout
<<
"Usage:
\n\t
"
<<
prog
<<
" <options>
\n\n
"
;
std
::
cout
<<
"-b <mbuf name> - The name of the mbuf to write to [edc_daq]
\n
"
;
std
::
cout
<<
"-d <dcu id> - The dcu id number to use [52]
\n
"
;
std
::
cout
<<
"-i <ini file name> - The ini file to read [edc.ini]
\n
"
;
std
::
cout
<<
"-w <wait time in ms> - Number of ms to wait after each 16Hz "
"segment has starts [0]
\n
"
;
std
::
cout
<<
"-p <prefix> - Prefix to add to the connection stats channel "
"names
\n
"
;
std
::
cout
<<
"-l <interface:port> - Where to bind to for the diagnostic "
"http output
\n
"
;
std
::
cout
<<
"-h - this help
\n
"
;
std
::
cout
<<
"
\n
The standalone edcu is used to record epics data and put "
"it into a memory buffer which can "
;
...
...
@@ -712,6 +851,20 @@ usage( const char* prog )
std
::
cout
<<
"
\n
"
;
}
std
::
pair
<
std
::
string
,
int
>
parse_address
(
const
std
::
string
&
str
)
{
std
::
string
hostname
=
str
;
int
port
=
20222
;
auto
pos
=
str
.
find
(
':'
);
if
(
pos
!=
std
::
string
::
npos
)
{
hostname
=
str
.
substr
(
0
,
pos
);
port
=
std
::
stoi
(
str
.
substr
(
pos
+
1
)
);
}
return
std
::
make_pair
(
std
::
move
(
hostname
),
port
);
}
/// Called on EPICS startup; This is generic EPICS provided function, modified
/// for LIGO use.
int
...
...
@@ -721,6 +874,14 @@ main( int argc, char* argv[] )
// Initialize request for file load on startup.
int
send_daq_reset
=
0
;
diag_queue_t
diag_msg_queue
;
diag_queue_t
diag_free_queue
;
diag_info_block
diag_info
[
DIAG_QUEUE_DEPTH
];
for
(
int
i
=
0
;
i
<
DIAG_QUEUE_DEPTH
;
++
i
)
{
diag_free_queue
.
push
(
&
(
diag_info
[
i
]
)
);
}
const
char
*
daqsharedmemname
=
"edc_daq"
;
// const char* syncsharedmemname = "-";
const
char
*
daqFile
=
"edc.ini"
;
...
...
@@ -728,8 +889,10 @@ main( int argc, char* argv[] )
int
delay_multiplier
=
0
;
diag_thread_args
diag_args
(
diag_msg_queue
,
diag_free_queue
);
int
cur_arg
=
0
;
while
(
(
cur_arg
=
getopt
(
argc
,
argv
,
"b:i:w:p:h"
)
)
!=
EOF
)
while
(
(
cur_arg
=
getopt
(
argc
,
argv
,
"b:i:w:p:
l:
h"
)
)
!=
EOF
)
{
switch
(
cur_arg
)
{
...
...
@@ -745,6 +908,9 @@ main( int argc, char* argv[] )
case
'p'
:
prefix
=
optarg
;
break
;
case
'l'
:
diag_args
.
address
=
parse_address
(
optarg
);
break
;
case
'h'
:
default:
usage
(
argv
[
0
]
);
...
...
@@ -798,6 +964,9 @@ main( int argc, char* argv[] )
int
cyle
=
0
;
update_diag_info
(
diag_args
.
queues
);
std
::
thread
diag_thread
(
diag_thread_mainloop
,
&
diag_args
);
// Start Infinite Loop
// *******************************************************************************
for
(
;;
)
...
...
@@ -822,7 +991,196 @@ main( int argc, char* argv[] )
cycle
=
(
cycle
+
1
)
%
16
;
transmit_time
=
transmit_time
+
time_step
;
if
(
cycle
==
0
)
{
update_diag_info
(
diag_args
.
queues
);
}
}
return
(
0
);
}
/*!
* @brief Route to be called from the main thread to send a diag blog to the
* diag thread. This holds a snapshot of the status of the channels and
* connections.
* @param queues The set of queues used to communicate with between the threads
*/
void
update_diag_info
(
diag_thread_queues
&
queues
)
{
if
(
!
queues
.
free_queue
.
read_available
(
)
)
{
return
;
}
diag_info_block
*
info
=
nullptr
;
queues
.
free_queue
.
pop
(
&
info
);
info
->
con_chans
=
daqd_edcu1
.
con_chans
;
std
::
copy
(
std
::
begin
(
daqd_edcu1
.
channel_status
),
std
::
begin
(
daqd_edcu1
.
channel_status
)
+
daqd_edcu1
.
num_chans
,
std
::
begin
(
info
->
status
)
);
queues
.
msg_queue
.
push
(
info
);
}
/*!
* @brief handler called from the diag thread periodically to pull diag
* information out of the shared diag message queue.
* @param queues The queues used to communicate with the main thread
* @param dest The data block to copy the diag information to.
*/
void
get_diag_info
(
diag_thread_queues
&
queues
,
diag_info_block
&
dest
)
{
if
(
!
queues
.
msg_queue
.
read_available
(
)
)
{
return
;
}
diag_info_block
*
info
=
nullptr
;
queues
.
msg_queue
.
pop
(
&
info
);
dest
=
*
info
;
queues
.
free_queue
.
push
(
info
);
}
/*!
* @brief timer callback for get_diag_info, this just ensure the get_diag_info
* is called and resets the time
* @param timer the timer
* @param queues The message queues
* @param dest where to write the diag info
*/
void
get_diag_info_handler
(
boost
::
asio
::
deadline_timer
&
timer
,
diag_thread_queues
&
queues
,
diag_info_block
&
dest
)
{
get_diag_info
(
queues
,
dest
);
timer
.
expires_from_now
(
boost
::
posix_time
::
seconds
(
1
)
);
timer
.
async_wait
(
[
&
timer
,
&
queues
,
&
dest
](
const
boost
::
system
::
error_code
&
)
{
get_diag_info_handler
(
timer
,
queues
,
dest
);
}
);
}
void
accept_loop
(
io_context_t
&
io_context
,
tcp
::
acceptor
&
acceptor
,
const
diag_info_block
&
cur_diag
);
void
client_write
(
std
::
shared_ptr
<
diag_client_conn
>
conn
)
{
rapidjson
::
StringBuffer
s
;
rapidjson
::
Writer
<
rapidjson
::
StringBuffer
>
writer
(
s
);
writer
.
StartObject
(
);
writer
.
Key
(
"TotalChannels"
);
writer
.
Int
(
daqd_edcu1
.
num_chans
);
writer
.
Key
(
"ConnectedChannelCount"
);
writer
.
Int
(
conn
->
data
.
con_chans
);
writer
.
Key
(
"DisconnectedChannelCount"
);
writer
.
Int
(
daqd_edcu1
.
num_chans
-
conn
->
data
.
con_chans
);
writer
.
Key
(
"DisconnectedChannels"
);
writer
.
StartArray
(
);
for
(
int
i
=
0
;
i
<
daqd_edcu1
.
num_chans
;
++
i
)
{
if
(
conn
->
data
.
status
[
i
]
!=
0
)
{
writer
.
String
(
daqd_edcu1
.
channel_name
[
i
]
);
}
}
writer
.
EndArray
(
);
writer
.
EndObject
(
);
std
::
ostringstream
os
;
os
<<
std
::
hex
<<
s
.
GetSize
(
)
<<
"
\r\n
"
;
conn
->
buffer
=
os
.
str
(
)
+
std
::
string
(
s
.
GetString
(
),
s
.
GetSize
(
)
)
+
std
::
string
(
"
\r\n
0
\r\n\r\n
"
);
boost
::
asio
::
async_write
(
conn
->
socket
,
boost
::
asio
::
buffer
(
conn
->
buffer
),
[
conn
](
const
boost
::
system
::
error_code
&
ec
,
std
::
size_t
)
{
if
(
!
ec
)
{
}
}
);
}
void
start_client_write
(
std
::
shared_ptr
<
diag_client_conn
>
conn
)
{
static
std
::
string
header
{
"HTTP/1.1 200 Ok
\r\n
"
"Content-Type: application/json
\r\n
"
"Cache-Control: max-age=1
\r\n
"
"Transfer-Encoding: chunked
\r\n
"
"Connection: close
\r\n\r\n
"
};
boost
::
asio
::
async_write
(
conn
->
socket
,
boost
::
asio
::
buffer
(
header
),
[
conn
](
const
boost
::
system
::
error_code
&
ec
,
std
::
size_t
)
{
if
(
!
ec
)
{
client_write
(
conn
);
}
}
);
}
void
handle_accept
(
io_context_t
&
io_context
,
tcp
::
acceptor
&
acceptor
,
std
::
shared_ptr
<
diag_client_conn
>
conn
,
const
boost
::
system
::
error_code
&
ec
,
const
diag_info_block
&
cur_diag
)
{
if
(
!
ec
)
{
conn
->
data
=
cur_diag
;
}
std
::
cerr
<<
"Accepting a new connection
\n
"
;
conn
->
io_context
.
post
(
[
conn
](
)
{
start_client_write
(
conn
);
}
);
accept_loop
(
io_context
,
acceptor
,
cur_diag
);
}
void
accept_loop
(
io_context_t
&
io_context
,
tcp
::
acceptor
&
acceptor
,
const
diag_info_block
&
cur_diag
)
{
std
::
shared_ptr
<
diag_client_conn
>
conn
=
std
::
make_shared
<
diag_client_conn
>
(
io_context
);
acceptor
.
async_accept
(
conn
->
socket
,
[
&
io_context
,
&
acceptor
,
conn
,
&
cur_diag
](
const
boost
::
system
::
error_code
&
ec
)
{
handle_accept
(
io_context
,
acceptor
,
conn
,
ec
,
cur_diag
);
}
);
}
/*!
* @brief the diag thread main loop
* @param args Arguments to the diag thread
*/
void
diag_thread_mainloop
(
diag_thread_args
*
args
)
{
diag_info_block
cur_diag
;
io_context_t
io_context
;
io_context_t
::
work
net_work
(
io_context
);
boost
::
asio
::
deadline_timer
diag_timer
(
io_context
);
get_diag_info_handler
(
diag_timer
,
args
->
queues
,
cur_diag
);
tcp
::
acceptor
acceptor
(
io_context
,
tcp
::
endpoint
(
make_address
(
args
->
address
.
first
.
c_str
(
)
),
args
->
address
.
second
)
);
accept_loop
(
io_context
,
acceptor
,
cur_diag
);
io_context
.
run
(
);
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment