Welcome to mirror list, hosted at ThFree Co, Russian Federation.

comm.c « Src « Core « STM32 - github.com/ClusterM/famicom-dumper-writer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: df7815794bb65ebed025f3ecf5e783b516cea56d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include "comm.h"
#include "crc.h"
#include "usbd_cdc_if.h"

uint8_t send_buffer[SEND_BUFFER_SIZE];
volatile uint16_t send_buffer_pos = 0;
static uint8_t comm_send_crc;     // CRC of outgoing packet with header
static uint16_t comm_send_length; // size of outgoing data
static uint16_t comm_send_pos;    // how many data sent by app

volatile uint8_t recv_buffer[RECV_BUFFER_SIZE];
static uint16_t comm_recv_pos; // how many bytes of packet received
static uint8_t comm_recv_crc;
static uint8_t comm_recv_error;
volatile uint8_t comm_recv_command;
volatile uint16_t comm_recv_length;
volatile uint8_t comm_recv_done;

extern DMA_HandleTypeDef hdma_memtomem_dma1_channel1;
extern volatile uint8_t dma_done;

static uint8_t comm_flush(void)
{
  uint32_t start_time = HAL_GetTick();
  uint8_t res;
  do
  {
    if (HAL_GetTick() >= start_time + SEND_TIMEOUT) // timeout
    {
      comm_init();
      return 0;
    }
    res = CDC_Transmit_FS((uint8_t*) send_buffer, send_buffer_pos);
  } while (res != USBD_OK);
  send_buffer_pos = 0;
  return 1;
}

static void comm_send_and_calc(uint8_t data)
{
  comm_send_crc = calc_crc8(comm_send_crc, data);
  send_buffer[send_buffer_pos++] = data;
}

static uint8_t check_send_buffer()
{
  uint8_t ok = 1;
  if (comm_send_pos >= comm_send_length)
  {
    send_buffer[send_buffer_pos++] = comm_send_crc;
    ok &= comm_flush();
  } else if (send_buffer_pos >= sizeof(send_buffer))
  {
    ok &= comm_flush();
  }
  return ok;
}

uint8_t comm_start(uint8_t command, uint16_t length)
{
  comm_send_crc = 0;
  send_buffer_pos = 0;
  comm_send_pos = 0;
  comm_send_and_calc('F');
  comm_send_and_calc(command);
  comm_send_and_calc(length & 0xff);
  comm_send_and_calc((length >> 8) & 0xff);
  comm_send_length = length;
  return check_send_buffer();
}

uint8_t comm_send_byte(uint8_t data)
{
  comm_send_and_calc(data);
  comm_send_pos++;
  return check_send_buffer();
}

uint8_t comm_send(uint8_t *address, uint16_t length)
{
  while (length)
  {
    if (!comm_send_byte(*address))
      return 0;
    address++;
    length--;
  }
  return 1;
}

void comm_proceed(uint8_t data)
{
  if (comm_recv_error && data != 'F')
    return;
  comm_recv_error = 0;
  if (!comm_recv_pos)
  {
    comm_recv_crc = 0;
    comm_recv_done = 0;
  }
  comm_recv_crc = calc_crc8(comm_recv_crc, data);
  switch (comm_recv_pos)
  {
  case 0:
    {
      if (data != 'F')
      {
        comm_recv_error = 1;
        comm_start(COMMAND_ERROR_INVALID, 0);
      }
    }
    break;
  case 1:
    {
      comm_recv_command = data;
    }
    break;
  case 2:
    {
      comm_recv_length = data;
    }
    break;
  case 3:
    {
      comm_recv_length |= (uint16_t) data << 8;
    }
    break;
  default:
    {
      uint16_t pos = comm_recv_pos - 4;
      if (pos >= sizeof(recv_buffer))
      {
        comm_recv_pos = 0;
        comm_recv_error = 1;
        comm_start(COMMAND_ERROR_OVERFLOW, 0);
        return;
      } else if (pos < comm_recv_length)
      {
        recv_buffer[pos] = data;
      } else if (pos == comm_recv_length)
      {
        if (!comm_recv_crc)
        {
          comm_recv_done = 1;
        } else
        {
          comm_recv_error = 1;
          comm_start(COMMAND_ERROR_CRC, 0);
        }
        comm_recv_pos = 0;
        return;
      }
    }
    break;
  }
  comm_recv_pos++;
}

void comm_init()
{
  send_buffer_pos = 0;
  comm_send_crc = 0;
  comm_send_length = 0;
  comm_send_pos = 0;
  comm_recv_pos = 0;
  comm_recv_crc = 0;
  comm_recv_error = 0;
  comm_recv_command = 0;
  comm_recv_length = 0;
  comm_recv_done = 0;
}