/*
 * slip-filter.hpp
 *
 *  Created on: 31 окт. 2018 г.
  *      Author: alexrayne <alexraynepe196@gmail.com>
  ------------------------------------------------------------------------
    Copyright (c) alexrayne

   All rights reserved.
   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:
   - Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
   - Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in the
     documentation and/or other materials provided with the distribution.
   - Neither the name of ARM nor the names of its contributors may be used
     to endorse or promote products derived from this software without
     specific prior written permission.
   *
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE. *
  ------------------------------------------------------------------------
 * */

#ifndef HAL_SLIP_FILTER_HPP_
#define HAL_SLIP_FILTER_HPP_

#include <lib/hal_ringbuffer.h>

//  класс делает фильтрацию SLIP протокола прямо на приемном буфере.
class SLIPBufFilter {
    public:
        typedef HAL_RingBuffer buffer_t;
        typedef HAL_RingBuffer::value_p value_p;
        typedef u8  value_t;
        typedef void (*PacketEventHandle)(SLIPBufFilter* self);

        /// \brief Key constants used in the SLIP protocol.
        enum
        {
            END = 0300,
            ESC = 0333,
            ESC_END = 0334,
            ESC_ESC = 0335
        };

    protected:
        buffer_t*   rx;
        buffer_t    parsed;
        value_p     buf_head;
        int         frame_len() const {
            return parsed.DataSize();
        };
        PacketEventHandle   on_frame;

    public:
        SLIPBufFilter(buffer_t* src);
        void        reset();
        // назначене пользовательского обработчик обнаружения фрейма.
        void        handle_on_frame(PacketEventHandle ev) {on_frame = ev;};

        // это разрешение получать пустые фреймы - два последовательных END трактую как фрейм
        static const bool zero_frames_valid = false;

        // спросматривает поступившие в буфер данные и фильтрует их.
        int         on_receive_refresh();
        // \return frame size
        int         have_frame() const;
        // отбрасывает текущий фрейм, и готовит буфер приему нового
        void        leave_frame();
        const buffer_t&   frame() const {return parsed;};

        // \return dst encoded len
        static
        unsigned         encode(void* __restrict dst, const void* __restrict src, unsigned len);
        static
        unsigned         encode(void* __restrict dst, char c);

        // \return number leading chars that are not special ESCaping
        static
        unsigned strcspn(const void* src, unsigned len);
        static
        unsigned strcspn(const void* src);

    protected:
        // clears parsed stream at buf_head position
        void        clear_parsed();

        //  decode data from buf_head block size len
        // \arg     buf_head - moves to end decoded source
        // \return  decoded data len
        unsigned    decode(unsigned len);
        enum DecodeStates {
            dsNorm, dsESC, dsFrame
        };
        DecodeStates    state;

        class buf_head_guard{
            //хранит позицию записи буфера, и восстанавливает ее.
            public:
                buffer_t*   buf;
                value_p     end;
                buf_head_guard( buffer_t* x, value_p tail)
                : buf(x)
                {
                    end = buf->FreeBuf();
                    buf->FreeBufAssign(tail);
                };
                ~buf_head_guard(){
                    buf->FreeBufAssign(end);
                }
        };
};




#endif /* HAL_SLIP_FILTER_HPP_ */
