2020-01-21 19:34:23 +01:00
/** Node-type: CAN bus
*
2020-07-08 16:07:24 +02:00
* @ author Niklas Eiling < niklas . eiling @ eonerc . rwth - aachen . de >
2020-01-21 19:34:23 +01:00
* @ copyright 2014 - 2020 , Institute for Automation of Complex Power Systems , EONERC
* @ license GNU General Public License ( version 3 )
*
* VILLASnode
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-07-08 13:33:13 +02:00
# include <cstdio>
# include <cstdlib>
# include <cstring>
2020-07-08 16:06:57 +02:00
# include <unistd.h>
# include <net/if.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/ioctl.h>
# include <linux/can.h>
# include <linux/can/raw.h>
2020-07-08 16:07:24 +02:00
# include <linux/sockios.h>
2020-07-08 16:06:57 +02:00
2021-06-21 16:11:42 -04:00
# include <villas/node.h>
2020-01-21 19:34:23 +01:00
# include <villas/nodes/can.hpp>
# include <villas/utils.hpp>
# include <villas/sample.h>
2020-07-08 13:32:08 +02:00
# include <villas/signal.h>
2021-02-16 14:15:14 +01:00
# include <villas/exceptions.hpp>
2020-01-21 19:34:23 +01:00
2020-07-08 13:32:08 +02:00
/* Forward declarations */
2021-06-21 16:11:42 -04:00
static struct vnode_type p ;
2020-01-21 19:34:23 +01:00
2021-02-16 14:15:14 +01:00
using namespace villas ;
2020-01-21 19:34:23 +01:00
using namespace villas : : node ;
using namespace villas : : utils ;
2020-08-25 21:00:52 +02:00
int can_init ( struct vnode * n )
2020-01-21 19:34:23 +01:00
{
struct can * c = ( struct can * ) n - > _vd ;
2020-07-08 16:06:57 +02:00
c - > interface_name = nullptr ;
c - > socket = 0 ;
2020-07-08 16:07:57 +02:00
c - > sample_buf = nullptr ;
2020-07-08 16:08:00 +02:00
c - > sample_buf_num = 0 ;
2020-07-08 16:07:57 +02:00
c - > in = nullptr ;
c - > out = nullptr ;
2020-01-21 19:34:23 +01:00
return 0 ;
}
2020-08-25 21:00:52 +02:00
int can_destroy ( struct vnode * n )
2020-01-21 19:34:23 +01:00
{
struct can * c = ( struct can * ) n - > _vd ;
2020-07-08 16:07:48 +02:00
free ( c - > interface_name ) ;
2020-07-08 13:33:58 +02:00
if ( c - > socket ! = 0 )
2020-07-08 16:07:48 +02:00
close ( c - > socket ) ;
2020-07-08 13:33:58 +02:00
2020-07-08 16:07:57 +02:00
free ( c - > sample_buf ) ;
2021-02-16 14:15:14 +01:00
if ( c - > in )
free ( c - > in ) ;
if ( c - > out )
free ( c - > out ) ;
2020-07-08 13:33:58 +02:00
2020-01-21 19:34:23 +01:00
return 0 ;
}
2021-05-10 00:12:30 +02:00
static int can_parse_signal ( json_t * json , struct vlist * node_signals , struct can_signal * can_signals , size_t signal_index )
2020-07-08 16:07:32 +02:00
{
2020-07-08 16:07:48 +02:00
const char * name = nullptr ;
uint64_t can_id = 0 ;
int can_size = 8 ;
int can_offset = 0 ;
struct signal * sig = nullptr ;
int ret = 1 ;
json_error_t err ;
2020-07-08 16:07:51 +02:00
ret = json_unpack_ex ( json , & err , 0 , " { s?: s, s?: i, s?: i, s?: i } " ,
2020-07-08 13:33:58 +02:00
" name " , & name ,
" can_id " , & can_id ,
" can_size " , & can_size ,
" can_offset " , & can_offset
) ;
2021-02-16 14:15:14 +01:00
if ( ret )
throw ConfigError ( json , err , " node-config-node-can-signals " ) ;
2020-07-08 16:07:48 +02:00
2021-02-16 14:15:14 +01:00
if ( can_size > 8 | | can_size < = 0 )
throw ConfigError ( json , " node-config-node-can-can-size " , " can_size of {} for signal '{}' is invalid. You must satisfy 0 < can_size <= 8. " , can_size , name ) ;
2020-07-08 16:07:48 +02:00
2021-02-16 14:15:14 +01:00
if ( can_offset > 8 | | can_offset < 0 )
throw ConfigError ( json , " node-config-node-can-can-offset " , " can_offset of {} for signal '{}' is invalid. You must satisfy 0 <= can_offset <= 8. " , can_offset , name ) ;
2020-07-08 16:07:48 +02:00
2020-07-08 16:07:51 +02:00
sig = ( struct signal * ) vlist_at ( node_signals , signal_index ) ;
if ( ( ! name & & ! sig - > name ) | | ( name & & strcmp ( name , sig - > name ) = = 0 ) ) {
can_signals [ signal_index ] . id = can_id ;
can_signals [ signal_index ] . size = can_size ;
can_signals [ signal_index ] . offset = can_offset ;
ret = 0 ;
goto out ;
2020-07-08 16:07:48 +02:00
}
2020-07-08 13:33:58 +02:00
else
2021-02-16 14:15:14 +01:00
throw ConfigError ( json , " node-config-node-can-signa;s " , " Signal configuration inconsistency detected: Signal with index {} '{}' does not match can_signal '{}' " , signal_index , sig - > name , name ) ;
2020-07-08 13:33:58 +02:00
out : return ret ;
2020-07-08 16:07:32 +02:00
}
2021-02-16 14:15:14 +01:00
int can_parse ( struct vnode * n , json_t * json )
2020-01-21 19:34:23 +01:00
{
2020-07-08 16:07:24 +02:00
int ret = 1 ;
2020-01-21 19:34:23 +01:00
struct can * c = ( struct can * ) n - > _vd ;
2020-07-08 16:07:48 +02:00
size_t i ;
json_t * json_in_signals ;
json_t * json_out_signals ;
json_t * json_signal ;
2020-01-21 19:34:23 +01:00
json_error_t err ;
2020-07-08 16:07:48 +02:00
c - > in = nullptr ;
c - > out = nullptr ;
2020-07-08 16:07:24 +02:00
2021-02-16 14:15:14 +01:00
ret = json_unpack_ex ( json , & err , 0 , " { s: s, s: F, s?: { s?: o }, s?: { s?: o } } " ,
2020-07-08 13:33:58 +02:00
" interface_name " , & c - > interface_name ,
" sample_rate " , & c - > sample_rate ,
" in " ,
" signals " , & json_in_signals ,
" out " ,
" signals " , & json_out_signals
) ;
2021-02-16 14:15:14 +01:00
if ( ret )
throw ConfigError ( json , err , " node-config-node-can " ) ;
2020-07-08 16:07:48 +02:00
2021-02-16 14:15:14 +01:00
c - > in = ( struct can_signal * ) calloc (
2020-07-08 16:07:51 +02:00
json_array_size ( json_in_signals ) ,
2021-02-16 14:15:14 +01:00
sizeof ( struct can_signal ) ) ;
if ( ! c - > in )
throw MemoryAllocationError ( ) ;
c - > out = ( struct can_signal * ) calloc (
2020-07-08 16:07:51 +02:00
json_array_size ( json_out_signals ) ,
2021-02-16 14:15:14 +01:00
sizeof ( struct can_signal ) ) ;
if ( c - > out )
throw MemoryAllocationError ( ) ;
2020-07-08 16:07:48 +02:00
json_array_foreach ( json_in_signals , i , json_signal ) {
2021-02-16 14:15:14 +01:00
ret = can_parse_signal ( json_signal , & n - > in . signals , c - > in , i ) ;
if ( ret )
throw RuntimeError ( " at signal {}. " , i ) ;
2020-07-08 16:07:48 +02:00
}
2020-07-08 13:33:58 +02:00
2020-07-08 16:07:48 +02:00
json_array_foreach ( json_out_signals , i , json_signal ) {
2021-02-16 14:15:14 +01:00
ret = can_parse_signal ( json_signal , & n - > out . signals , c - > out , i ) ;
if ( ret )
throw RuntimeError ( " at signal {}. " , i ) ;
2020-07-08 16:07:24 +02:00
}
2020-07-08 13:33:58 +02:00
2020-07-08 16:07:48 +02:00
ret = 0 ;
2020-07-08 13:33:58 +02:00
2020-07-08 16:07:24 +02:00
return ret ;
2020-01-21 19:34:23 +01:00
}
2020-08-25 21:00:52 +02:00
char * can_print ( struct vnode * n )
2020-01-21 19:34:23 +01:00
{
struct can * c = ( struct can * ) n - > _vd ;
2021-02-16 14:15:14 +01:00
return strf ( " interface_name={} " , c - > interface_name ) ;
2020-01-21 19:34:23 +01:00
}
2020-08-25 21:00:52 +02:00
int can_check ( struct vnode * n )
2020-01-21 19:34:23 +01:00
{
struct can * c = ( struct can * ) n - > _vd ;
2021-02-16 14:15:14 +01:00
if ( c - > interface_name = = nullptr | | strlen ( c - > interface_name ) = = 0 )
throw RuntimeError ( " Empty interface_name. Please specify the name of the CAN interface! " ) ;
2020-01-21 19:34:23 +01:00
return 0 ;
}
2020-08-25 21:00:52 +02:00
int can_prepare ( struct vnode * n )
2020-01-21 19:34:23 +01:00
{
2020-07-08 16:07:57 +02:00
struct can * c = ( struct can * ) n - > _vd ;
2020-07-08 13:33:58 +02:00
c - > sample_buf = ( union signal_data * ) calloc ( vlist_length ( & n - > in . signals ) , sizeof ( union signal_data ) ) ;
2020-07-08 16:07:57 +02:00
return ( c - > sample_buf ! = 0 ? 0 : 1 ) ;
2020-01-21 19:34:23 +01:00
}
2020-08-25 21:00:52 +02:00
int can_start ( struct vnode * n )
2020-01-21 19:34:23 +01:00
{
2020-07-08 16:07:57 +02:00
int ret = 1 ;
2020-07-08 16:06:57 +02:00
struct sockaddr_can addr = { 0 } ;
struct ifreq ifr ;
2020-01-21 19:34:23 +01:00
struct can * c = ( struct can * ) n - > _vd ;
2020-07-08 16:06:57 +02:00
c - > start_time = time_now ( ) ;
2020-01-21 19:34:23 +01:00
2021-02-16 14:15:14 +01:00
c - > socket = socket ( PF_CAN , SOCK_RAW , CAN_RAW ) ;
if ( c - > socket < 0 )
throw SystemError ( " Error while opening CAN socket " ) ;
2020-01-21 19:34:23 +01:00
2020-07-08 16:06:57 +02:00
strcpy ( ifr . ifr_name , c - > interface_name ) ;
2021-02-16 14:15:14 +01:00
ret = ioctl ( c - > socket , SIOCGIFINDEX , & ifr ) ;
if ( ret ! = 0 )
throw SystemError ( " Could not find interface with name '{}'. " , c - > interface_name ) ;
2020-07-08 16:06:57 +02:00
addr . can_family = AF_CAN ;
addr . can_ifindex = ifr . ifr_ifindex ;
2021-02-16 14:15:14 +01:00
ret = bind ( c - > socket , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
if ( ret < 0 )
throw SystemError ( " Could not bind to interface with name '{}' ({}) . " , c->interface_name, ifr.ifr_ifindex) ;
2020-07-08 13:33:58 +02:00
2021-02-16 14:15:14 +01:00
return 0 ;
2020-01-21 19:34:23 +01:00
}
2020-08-25 21:00:52 +02:00
int can_stop ( struct vnode * n )
2020-01-21 19:34:23 +01:00
{
2020-07-08 16:06:57 +02:00
struct can * c = ( struct can * ) n - > _vd ;
2020-01-21 19:34:23 +01:00
2020-07-08 16:07:48 +02:00
if ( c - > socket ! = 0 ) {
close ( c - > socket ) ;
c - > socket = 0 ;
}
2020-01-21 19:34:23 +01:00
return 0 ;
}
2021-05-10 00:12:30 +02:00
static int can_convert_to_raw ( const union signal_data * sig , const struct signal * from , void * to , int size )
2020-07-08 16:08:00 +02:00
{
2021-02-16 14:15:14 +01:00
if ( size < = 0 | | size > 8 )
throw RuntimeError ( " Signal size cannot be larger than 8! " ) ;
2020-07-08 13:33:58 +02:00
2020-07-08 16:08:00 +02:00
switch ( from - > type ) {
2020-07-08 13:33:58 +02:00
case SignalType : : BOOLEAN :
* ( uint8_t * ) to = sig - > b ;
2020-07-08 16:08:00 +02:00
return 0 ;
2020-07-08 13:33:58 +02:00
case SignalType : : INTEGER :
switch ( size ) {
case 1 :
* ( int8_t * ) to = ( int8_t ) sig - > i ;
return 0 ;
case 2 :
* ( int16_t * ) to = ( int16_t ) sig - > i ;
return 0 ;
case 3 :
* ( int16_t * ) to = ( int16_t ) sig - > i ;
* ( ( int8_t * ) to + 2 ) = ( int8_t ) ( sig - > i > > 16 ) ;
return 0 ;
case 4 :
* ( int32_t * ) to = ( int32_t ) sig - > i ;
return 0 ;
case 8 :
* ( int64_t * ) to = sig - > i ;
return 0 ;
default :
goto fail ;
}
case SignalType : : FLOAT :
switch ( size ) {
case 4 :
assert ( sizeof ( float ) = = 4 ) ;
* ( float * ) to = ( float ) sig - > f ;
return 0 ;
case 8 :
* ( double * ) to = sig - > f ;
return 0 ;
default :
goto fail ;
}
case SignalType : : COMPLEX :
if ( size ! = 8 )
goto fail ;
* ( float * ) to = sig - > z . real ( ) ;
* ( ( float * ) to + 1 ) = sig - > z . imag ( ) ;
2020-07-08 16:08:00 +02:00
return 0 ;
2020-07-08 13:33:58 +02:00
2020-07-08 16:08:00 +02:00
default :
goto fail ;
}
2020-07-08 13:33:58 +02:00
2021-02-16 14:15:14 +01:00
fail :
throw RuntimeError ( " Unsupported conversion to {} from raw ({}, {}) " , signal_type_to_str(from->type), to, size) ;
2020-07-08 13:33:58 +02:00
2020-07-08 16:08:00 +02:00
return 1 ;
}
2020-07-08 16:07:57 +02:00
int can_conv_from_raw ( union signal_data * sig , void * from , int size , struct signal * to )
{
2021-02-16 14:15:14 +01:00
if ( size < = 0 | | size > 8 )
throw RuntimeError ( " Signal size cannot be larger than 8! " ) ;
2020-07-08 13:33:58 +02:00
2020-07-08 16:07:57 +02:00
switch ( to - > type ) {
2020-07-08 13:33:58 +02:00
case SignalType : : BOOLEAN :
sig - > b = ( bool ) * ( uint8_t * ) from ;
2020-07-08 16:07:57 +02:00
return 0 ;
2020-07-08 13:33:58 +02:00
case SignalType : : INTEGER :
switch ( size ) {
case 1 :
sig - > i = ( int64_t ) * ( int8_t * ) from ;
return 0 ;
case 2 :
sig - > i = ( int64_t ) * ( int16_t * ) from ;
return 0 ;
case 3 :
sig - > i = ( int64_t ) * ( int16_t * ) from ;
sig - > i + = ( ( int64_t ) * ( ( int8_t * ) ( from ) + 2 ) ) < < 16 ;
return 0 ;
case 4 :
sig - > i = ( int64_t ) * ( int32_t * ) from ;
return 0 ;
case 8 :
sig - > i = * ( uint64_t * ) from ;
return 0 ;
default :
goto fail ;
}
case SignalType : : FLOAT :
switch ( size ) {
case 4 :
assert ( sizeof ( float ) = = 4 ) ;
sig - > f = ( double ) * ( float * ) from ;
return 0 ;
case 8 :
sig - > f = * ( double * ) from ;
return 0 ;
default :
goto fail ;
}
case SignalType : : COMPLEX :
if ( size ! = 8 )
goto fail ;
sig - > z = std : : complex < float > ( * ( float * ) from , * ( ( float * ) from + 1 ) ) ;
2020-07-08 16:07:57 +02:00
return 0 ;
2020-07-08 13:33:58 +02:00
2020-07-08 16:07:57 +02:00
default :
2020-07-08 16:08:00 +02:00
goto fail ;
2020-07-08 16:07:57 +02:00
}
2020-07-08 13:33:58 +02:00
fail :
2021-02-16 14:15:14 +01:00
throw RuntimeError ( " Unsupported conversion from {} to raw ({}, {}) " , signal_type_to_str(to->type), from, size) ;
2020-07-08 13:33:58 +02:00
2020-07-08 16:08:00 +02:00
return 1 ;
2020-07-08 16:07:57 +02:00
}
2021-05-10 00:12:30 +02:00
int can_read ( struct vnode * n , struct sample * const smps [ ] , unsigned cnt )
2020-01-21 19:34:23 +01:00
{
2020-07-08 16:08:00 +02:00
int ret = 0 ;
2020-07-08 16:06:57 +02:00
int nbytes ;
2020-07-08 16:07:48 +02:00
unsigned nread = 0 ;
2020-07-08 16:06:57 +02:00
struct can_frame frame ;
2020-07-08 16:07:48 +02:00
struct timeval tv ;
bool found_id = false ;
2020-01-21 19:34:23 +01:00
2020-07-08 16:06:57 +02:00
struct can * c = ( struct can * ) n - > _vd ;
2020-01-21 19:34:23 +01:00
assert ( cnt > = 1 & & smps [ 0 ] - > capacity > = 1 ) ;
2020-07-08 16:07:48 +02:00
nbytes = read ( c - > socket , & frame , sizeof ( struct can_frame ) ) ;
2021-02-16 14:15:14 +01:00
if ( nbytes = = - 1 )
throw RuntimeError ( " CAN read() returned - 1. Is the CAN interface up ? " ) ;
2020-07-08 13:33:58 +02:00
2021-02-16 14:15:14 +01:00
if ( ( unsigned ) nbytes ! = sizeof ( struct can_frame ) )
throw RuntimeError ( " CAN read() error . Returned { } bytes but expected { } " , nbytes, sizeof(struct can_frame));
2020-07-08 16:07:48 +02:00
2021-02-16 14:15:14 +01:00
n - > logger - > debug ( " Received can message: (id={}, len={}, data={:#x}:{:#x}) " ,
2020-07-08 13:33:58 +02:00
frame . can_id ,
frame . can_dlc ,
( ( uint32_t * ) & frame . data ) [ 0 ] ,
( ( uint32_t * ) & frame . data ) [ 1 ] ) ;
2020-07-08 16:07:48 +02:00
if ( ioctl ( c - > socket , SIOCGSTAMP , & tv ) = = 0 ) {
TIMEVAL_TO_TIMESPEC ( & tv , & smps [ nread ] - > ts . received ) ;
smps [ nread ] - > flags | = ( int ) SampleFlags : : HAS_TS_RECEIVED ;
}
for ( size_t i = 0 ; i < vlist_length ( & ( n - > in . signals ) ) ; i + + ) {
if ( c - > in [ i ] . id = = frame . can_id ) {
2020-07-08 16:07:57 +02:00
if ( can_conv_from_raw ( & c - > sample_buf [ i ] ,
( ( uint8_t * ) & frame . data ) + c - > in [ i ] . offset ,
c - > in [ i ] . size ,
2020-07-08 16:08:00 +02:00
( struct signal * ) vlist_at ( & n - > in . signals , i ) ) ! = 0 ) {
goto out ;
2020-07-08 16:07:57 +02:00
}
2020-07-08 13:33:58 +02:00
2020-07-08 16:08:00 +02:00
c - > sample_buf_num + + ;
2020-07-08 16:07:48 +02:00
found_id = true ;
}
}
2020-07-08 13:33:58 +02:00
2021-02-16 14:15:14 +01:00
if ( ! found_id )
throw RuntimeError ( " Did not find signal for can id {} " , frame . can_id ) ;
2020-07-08 13:33:58 +02:00
2021-02-16 14:15:14 +01:00
n - > logger - > debug ( " Received {} signals " , c - > sample_buf_num ) ;
2020-07-08 13:33:58 +02:00
2020-07-08 16:08:00 +02:00
/* Copy signal data to sample only when all signals have been received */
if ( c - > sample_buf_num = = vlist_length ( & n - > in . signals ) ) {
smps [ nread ] - > length = c - > sample_buf_num ;
memcpy ( smps [ nread ] - > data , c - > sample_buf , c - > sample_buf_num * sizeof ( union signal_data ) ) ;
c - > sample_buf_num = 0 ;
smps [ nread ] - > flags | = ( int ) SampleFlags : : HAS_DATA ;
ret = 1 ;
2020-07-08 13:33:58 +02:00
}
else {
2020-07-08 16:08:00 +02:00
smps [ nread ] - > length = 0 ;
ret = 0 ;
}
2020-07-08 13:33:58 +02:00
out : /* Set signals, because other VILLASnode parts expect us to */
2020-07-08 16:07:48 +02:00
smps [ nread ] - > signals = & n - > in . signals ;
2020-07-08 13:33:58 +02:00
2020-07-08 16:08:00 +02:00
return ret ;
2020-01-21 19:34:23 +01:00
}
2021-05-10 00:12:30 +02:00
int can_write ( struct vnode * n , struct sample * const smps [ ] , unsigned cnt )
2020-01-21 19:34:23 +01:00
{
2020-07-08 16:06:57 +02:00
int nbytes ;
2020-07-08 16:07:48 +02:00
unsigned nwrite ;
2020-07-08 16:07:28 +02:00
struct can_frame * frame ;
2020-07-08 16:07:48 +02:00
size_t fsize = 0 ; /* number of frames in use */
2020-07-08 16:07:28 +02:00
struct can * c = ( struct can * ) n - > _vd ;
assert ( cnt > = 1 & & smps [ 0 ] - > capacity > = 1 ) ;
2020-07-08 13:33:58 +02:00
frame = ( struct can_frame * ) calloc ( sizeof ( struct can_frame ) , vlist_length ( & ( n - > out . signals ) ) ) ;
2020-07-08 16:07:48 +02:00
for ( nwrite = 0 ; nwrite < cnt ; nwrite + + ) {
for ( size_t i = 0 ; i < vlist_length ( & ( n - > out . signals ) ) ; i + + ) {
2020-07-08 13:33:58 +02:00
if ( c - > out [ i ] . offset ! = 0 ) /* frame is shared */
2020-07-08 16:07:48 +02:00
continue ;
2020-07-08 13:33:58 +02:00
2020-07-08 16:07:48 +02:00
frame [ fsize ] . can_dlc = c - > out [ i ] . size ;
frame [ fsize ] . can_id = c - > out [ i ] . id ;
2020-07-08 13:33:58 +02:00
2021-05-10 00:12:30 +02:00
can_convert_to_raw (
2020-07-08 16:08:00 +02:00
& smps [ nwrite ] - > data [ i ] ,
( struct signal * ) vlist_at ( & ( n - > out . signals ) , i ) ,
& frame [ fsize ] . data ,
c - > out [ i ] . size ) ;
2020-07-08 13:33:58 +02:00
2020-07-08 16:07:48 +02:00
fsize + + ;
}
2020-07-08 13:33:58 +02:00
2020-07-08 16:07:48 +02:00
for ( size_t i = 0 ; i < vlist_length ( & ( n - > out . signals ) ) ; i + + ) {
if ( c - > out [ i ] . offset = = 0 ) { /* frame already stored */
continue ;
}
2020-07-08 13:33:58 +02:00
2020-07-08 16:07:48 +02:00
for ( size_t j = 0 ; j < fsize ; j + + ) {
2020-07-08 13:33:58 +02:00
if ( c - > out [ i ] . id ! = frame [ j ] . can_id )
2020-07-08 16:08:00 +02:00
continue ;
2020-07-08 13:33:58 +02:00
2020-07-08 16:08:00 +02:00
frame [ j ] . can_dlc + = c - > out [ i ] . size ;
2021-05-10 00:12:30 +02:00
can_convert_to_raw (
2020-07-08 16:08:00 +02:00
& smps [ nwrite ] - > data [ i ] ,
( struct signal * ) vlist_at ( & ( n - > out . signals ) , i ) ,
( uint8_t * ) & frame [ j ] . data + c - > out [ i ] . offset ,
c - > out [ i ] . size ) ;
break ;
2020-07-08 16:07:48 +02:00
}
}
2020-07-08 13:33:58 +02:00
2020-07-08 16:07:48 +02:00
for ( size_t j = 0 ; j < fsize ; j + + ) {
2021-02-16 14:15:14 +01:00
n - > logger - > debug ( " Writing CAN message: (id={}, dlc={}, data={:#x}:{:#x}) " ,
2020-07-08 13:33:58 +02:00
frame [ j ] . can_id ,
frame [ j ] . can_dlc ,
( ( uint32_t * ) & frame [ j ] . data ) [ 0 ] ,
( ( uint32_t * ) & frame [ j ] . data ) [ 1 ]
) ;
2020-07-08 16:07:48 +02:00
2021-02-16 14:15:14 +01:00
if ( ( nbytes = write ( c - > socket , & frame [ j ] , sizeof ( struct can_frame ) ) ) = = - 1 )
throw RuntimeError ( " CAN write() returned - 1. Is the CAN interface up ? " ) ;
2020-07-08 13:33:58 +02:00
2021-02-16 14:15:14 +01:00
if ( ( unsigned ) nbytes ! = sizeof ( struct can_frame ) )
throw RuntimeError ( " CAN write() returned { } bytes but expected { } " ,
2020-07-08 13:33:58 +02:00
nbytes , sizeof ( struct can_frame ) ) ;
2020-07-08 16:07:48 +02:00
}
}
2020-01-21 19:34:23 +01:00
2020-07-08 13:32:08 +02:00
return nwrite ;
2020-01-21 19:34:23 +01:00
}
2020-08-25 21:00:52 +02:00
int can_poll_fds ( struct vnode * n , int fds [ ] )
2020-01-21 19:34:23 +01:00
{
2020-07-08 16:07:39 +02:00
struct can * c = ( struct can * ) n - > _vd ;
2020-07-08 13:33:58 +02:00
2020-07-08 16:07:48 +02:00
fds [ 0 ] = c - > socket ;
2020-01-21 19:34:23 +01:00
2020-07-08 16:07:39 +02:00
return 1 ; /* The number of file descriptors which have been set in fds */
2020-01-21 19:34:23 +01:00
}
__attribute__ ( ( constructor ( 110 ) ) )
2020-07-08 13:32:08 +02:00
static void register_plugin ( ) {
2021-06-21 16:11:42 -04:00
p . name = " can " ;
p . description = " Receive CAN messages using the socketCAN driver " ;
p . vectorize = 0 ;
p . size = sizeof ( struct can ) ;
p . init = can_init ;
p . destroy = can_destroy ;
p . prepare = can_prepare ;
p . parse = can_parse ;
p . print = can_print ;
p . check = can_check ;
p . start = can_start ;
p . stop = can_stop ;
p . read = can_read ;
p . write = can_write ;
p . poll_fds = can_poll_fds ;
if ( ! node_types )
node_types = new NodeTypeList ( ) ;
node_types - > push_back ( & p ) ;
2020-07-08 13:32:08 +02:00
}