can.c 5.78 KB
/**
    @file     can.c
    @date     2012-02-24
    @author   장길석 jks@falinux.com
    @brief    can을 사용한 통신을 담당한다.

    @modify
              2010-08-18 (장길석) mingw와 함께 사용할 수 있는 코드 추가
    @todo
    @bug
    @remark

    @warning
*/
//
//  저작권    에프에이리눅스(주)
//            외부공개 금지
//
//----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>

#include <socketcan/can.h>
#include <socketcan/can/raw.h>
#include <socketcan/can/error.h>

#include <pollmng.h>
#include <can.h>

/// udp 개별 구조체
typedef struct {

    int                  im_server;
    struct sockaddr_can  addr;
} can_priv_t;

static poll_obj_t  *tmp_can_poll = NULL;  // poll 관리객체없이 전송함수를 위해

#define PF_CAN      29                      /* Controller Area Network.  */
#define AF_CAN      PF_CAN

//------------------------------------------------------------------------------
/** @brief    udp 소켓을 서버형태로 open 한다.
    @param    port  포트번호
    @return   poll_obj_t 형태의 포인터
*///----------------------------------------------------------------------------
poll_obj_t  *can_open( char *can_port, can_filter_t *rfilter, int filter_size)
{
    struct sockaddr_can  addr;
    poll_obj_t          *obj;
    can_priv_t          *can;
    int                  sockfd;

    struct ifreq        ifr;
    int                 ifindex;

    sockfd = socket( PF_CAN, SOCK_RAW, CAN_RAW);
    if ( sockfd < 0 ){
        perror( "can open error:" );
        return NULL;
    }
    setsockopt( sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, rfilter, filter_size);

    // 소켓을 시스템에 연결한다.
    bzero( &addr, sizeof(struct sockaddr_can) );

    strcpy( ifr.ifr_name, can_port);                         // 사용할 CAN 번호
    ioctl(sockfd, SIOCGIFINDEX, &ifr);
    ifindex = ifr.ifr_ifindex;

    addr.can_family     = AF_CAN;
    addr.can_ifindex    = ifindex;

    if( bind( sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0 )
    {
        perror("udp bind error :");
        close( sockfd );
        return NULL;
    }

    // udp 만의 정보를 설정한다.
    can = (can_priv_t *)malloc( sizeof(can_priv_t) );
    can->im_server  = 1;
    memcpy( &can->addr, &addr, sizeof( can->addr));

    obj             = poll_add( sockfd );
    obj->type       = STYP_CAN;
    obj->priv       = (void *)can;

    tmp_can_poll    = obj;

    return obj;
}

//------------------------------------------------------------------------------
/** @brief    udp 소켓을 close 한다.
    @param    obj  폴객체 포인터
*///----------------------------------------------------------------------------
void can_close( poll_obj_t *obj )
{
    close( obj->fd );

    if ( obj->priv )
    {
        free( obj->priv );
    }

    poll_delete( obj );

    if ( tmp_can_poll == obj ) tmp_can_poll = NULL;
}
//------------------------------------------------------------------------------
/** @brief    udp 소켓을 통해 데이타를 전송한다.
    @param    obj     폴객체 포인터
    @param    host    상대방 IP 나 호스트이름 문자열포인터
    @param    port    상대방 포트번호
    @param    buf     전송버퍼
    @param    len     버퍼의 길이
    @return   전송한 데이타 개수
*///----------------------------------------------------------------------------
int  can_write( poll_obj_t *obj, can_frame_t *frame)
{
    struct sockaddr_can     *p_addr;
    can_priv_t              *p_can;
    int                      wrcnt;

    p_can   = ( can_priv_t *)obj->priv;
    p_addr  = &p_can->addr;

    wrcnt = sendto( obj->fd, frame, sizeof( can_frame_t), 0, (struct sockaddr*)p_addr, sizeof( struct sockaddr_can));
    if ( 0 > wrcnt ){
        perror( "can send error:" );
    }
    return wrcnt;
}
//------------------------------------------------------------------------------
/** @brief    udp 소켓을 통해 데이타를 읽는다.
    @param    obj     폴객체 포인터
    @param    len     버퍼의 길이
    @return   전송된 데이타 개수
*///----------------------------------------------------------------------------
int  can_read( poll_obj_t *obj, can_frame_t *frame)
{
    int     rdcnt;

    rdcnt = read( obj->fd, frame, sizeof(can_frame_t));
    if ( 0 > rdcnt )
    {
        perror( "can recv error:" );
    }

    return rdcnt;
}
//------------------------------------------------------------------------------
/** @brief    poll 객체없이 udp 소켓을 통해 데이타를 전송한다.
    @param    host    상대방 IP 나 호스트이름 문자열포인터
    @param    port    상대방 포트번호
    @param    buf     전송버퍼
    @param    len     버퍼의 길이
    @return   전송한 데이타 개수
    @remark   can_open_server(), can_open_client() 함수는 한번 호출되어야 한다.
*///----------------------------------------------------------------------------
int  can_write_simple( can_frame_t *frame )
{
    if ( tmp_can_poll )
    {
        return can_write( tmp_can_poll, frame);
    }

    return -1;
}
//------------------------------------------------------------------------------
/** @brief    poll 객체없이 udp 소켓을 통해 데이타를 읽는다.
    @param    buf  전송버퍼
    @param    len  버퍼의 길이
    @return   전송된 데이타 개수
    @remark   can_open_server(), can_open_client() 함수는 한번 호출되어야 한다.
*///----------------------------------------------------------------------------
int  can_read_simple( can_frame_t *frame )
{
    if ( tmp_can_poll )
    {
        return can_read( tmp_can_poll, frame);
    }

    return -1;
}