GRBL-Advanced/Libraries/GrIP/GrIP.c

291 wiersze
7.1 KiB
C

/*
GrIP.c - GRBL over IP
Copyright (c) 2018-2019 Patrick F.
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
(at your option) 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 program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "GrIP.h"
#include "CRC.h"
#include "ServerTCP.h"
#include "ComIf.h"
#include "Print.h"
#include <stdio.h>
#include <string.h>
// GrIP states
#define GRIP_IDLE 0
#define GRIP_RX_HEADER 1
#define GRIP_RX_DATA 2
// Magic byte - Marks start of transmission
#define MAGIC 0x55
// Size of header packet
#define GRIP_HEADER_SIZE (sizeof(GrIP_PacketHeader_t))
static uint8_t CheckHeader(GrIP_PacketHeader_t *paket);
static GrIP_PacketHeader_t TX_Header;
// Transmit Buffer
static uint8_t TX_Buffer[GRIP_BUFFER_SIZE + GRIP_HEADER_SIZE];
// Receive Data Array
static RX_Packet_t RX_Buff[GRIP_RX_NUM] = {0};
static uint8_t GrIP_Status = GRIP_IDLE;
static uint8_t GrIP_Response = RESPONSE_OK;
static uint8_t GrIP_idx = 0;
void GrIP_Init(void)
{
// Initialize to default values
GrIP_Status = GRIP_IDLE;
GrIP_idx = 0;
memset(&TX_Header, 0, GRIP_HEADER_SIZE);
memset(TX_Buffer, 0, GRIP_BUFFER_SIZE + GRIP_HEADER_SIZE);
memset(RX_Buff, 0, sizeof(RX_Buff));
// Init generic interface
ComIf_Init(IF_ETH, 0);
}
uint8_t GrIP_Transmit(uint8_t MsgType, uint8_t ReturnCode, Pdu_t *data)
{
// Prepare header
TX_Header.Version = GRIP_VERSION;
TX_Header.MsgType = MsgType;
TX_Header.ReturnCode = ReturnCode;
if(data)
{
// Convert length to network order
TX_Header.Length = htons(data->Length);
// Check if data fits into transmit buffer
if(data->Length > GRIP_BUFFER_SIZE)
{
return RET_NOK;
}
else if(data->Length > 0)
{
// Calculate CRC of data
TX_Header.CRC8 = CRC_CalculateCRC8(data->Data, data->Length);
}
else
{
// No data, no CRC
TX_Header.CRC8 = 0;
}
// Prepare transmit buffer
TX_Buffer[0] = MAGIC;
memcpy(&TX_Buffer[1], &TX_Header, GRIP_HEADER_SIZE);
memcpy(&TX_Buffer[1] + GRIP_HEADER_SIZE, data->Data, data->Length);
// Transmit paket
ComIf_Send(TX_Buffer, data->Length + GRIP_HEADER_SIZE + 1);
// Check if we are expecting a response
GrIP_Response = RESPONSE_OK;
if(MsgType == MSG_DATA)
{
GrIP_Response = RESPONSE_WAIT;
}
return RET_OK;
}
else // Response
{
// No data available -> Response
// No data to transmit, only header
TX_Header.Length = 0;
memcpy(TX_Buffer, &TX_Header, GRIP_HEADER_SIZE);
// Transmit paket
ComIf_Send(TX_Buffer, GRIP_HEADER_SIZE);
return RET_OK;
}
// Clear memory
memset(&TX_Header, 0, GRIP_HEADER_SIZE);
memset(TX_Buffer, 0, GRIP_BUFFER_SIZE);
return RET_NOK;
}
uint8_t GrIP_Receive(RX_Packet_t *pData)
{
if(pData)
{
for(uint8_t i = 0; i < GRIP_RX_NUM; i++)
{
if(RX_Buff[i].isValid)
{
memcpy(pData, &RX_Buff[i], sizeof(RX_Packet_t));
// Clear rx slot
memset(&RX_Buff[i], 0, sizeof(RX_Packet_t));
return 1;
}
}
}
// No data available
return 0;
}
uint8_t GrIP_ResponseStatus(void)
{
return GrIP_Response;
}
void GrIP_Update(void)
{
switch(GrIP_Status)
{
case GRIP_IDLE:
// Check if data is available
if(ComIf_DataAvailable())
{
uint8_t magic = 0;
// Read Magic byte
ComIf_Receive(&magic, 1);
if(magic == MAGIC)
{
// Received valid packet
GrIP_Status = GRIP_RX_HEADER;
}
}
break;
case GRIP_RX_HEADER:
// Check if header is available
if(ComIf_DataAvailable() > (GRIP_HEADER_SIZE-1))
{
uint8_t head_buff[GRIP_HEADER_SIZE] = {0};
// Get header
ComIf_Receive(head_buff, GRIP_HEADER_SIZE);
// Fill struct
memcpy(&RX_Buff[GrIP_idx].RX_Header, head_buff, GRIP_HEADER_SIZE);
// Convert length to host order
RX_Buff[GrIP_idx].RX_Header.Length = ntohs(RX_Buff[GrIP_idx].RX_Header.Length);
// Check if header is valid
uint8_t ret = CheckHeader(&RX_Buff[GrIP_idx].RX_Header);
if(ret != RET_OK)
{
// Header is invalid
GrIP_Status = GRIP_IDLE;
//Printf("Wrong header: %d\n", ret);
break;
}
if(RX_Buff[GrIP_idx].RX_Header.Length > GRIP_BUFFER_SIZE)
{
// Payload too big
GrIP_Status = GRIP_IDLE;
//Printf("Payload exceeds limit: %d\n", RX_Buff[GrIP_idx].RX_Header.Length);
break;
}
// If payload is available
if(RX_Buff[GrIP_idx].RX_Header.Length)
{
// Payload is available
GrIP_Status = GRIP_RX_DATA;
}
else
{
// No payload
GrIP_Status = GRIP_IDLE;
RX_Buff[GrIP_idx].isValid = 1;
if(GrIP_idx < (GRIP_RX_NUM-1))
{
GrIP_idx++;
}
else
{
GrIP_idx = 0;
}
}
}
break;
case GRIP_RX_DATA:
// Check if entire payload is available
if(ComIf_DataAvailable() > (RX_Buff[GrIP_idx].RX_Header.Length-1))
{
// Get payload
//GenIf_Receive(RX_Buffer, RX_Header.Length);
ComIf_Receive(RX_Buff[GrIP_idx].Data, RX_Buff[GrIP_idx].RX_Header.Length);
if(RX_Buff[GrIP_idx].RX_Header.CRC8 == CRC_CalculateCRC8(RX_Buff[GrIP_idx].Data, RX_Buff[GrIP_idx].RX_Header.Length))
{
RX_Buff[GrIP_idx].isValid = 1;
if(GrIP_idx < (GRIP_RX_NUM-1))
{
GrIP_idx++;
}
else
{
GrIP_idx = 0;
}
}
GrIP_Status = GRIP_IDLE;
}
break;
}
// Check for new data
ComIf_Update();
}
static uint8_t CheckHeader(GrIP_PacketHeader_t *paket)
{
if(paket->Version != GRIP_VERSION)
{
// Wrong version
return RET_WRONG_VERSION;
}
if(paket->MsgType >= MSG_MAX_NUM)
{
// Wrong message type
return RET_WRONG_TYPE;
}
// Everything OK
return RET_OK;
}