GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src\circ.c Lines: 90 90 100.0 %
Date: 2019-11-27 20:04:21 Branches: 60 60 100.0 %

Line Branch Exec Source
1
#include "circ.h"
2
#include <stdio.h>
3
#include <string.h>
4
#include <stdbool.h>
5
6
7
#ifndef NELEMS
8
#define NELEMS(array) (sizeof(array) / sizeof(array[0]))
9
#endif
10
11
#ifndef ASSERT
12
#define CONCAT(a,b) a##b
13
#define __ASSERT(predicate, line) \
14
            typedef char CONCAT(assertion_failed, line)[2*!!(predicate)-1];
15
#define ASSERT(predicate) __ASSERT(predicate, __LINE__)
16
#endif
17
18
19
struct circ
20
{
21
    struct
22
    {
23
        size_t head;
24
        size_t tail;
25
        size_t size;
26
        bool full;
27
    }info;
28
    uint8_t *data;
29
};
30
31
static volatile struct circ buffers[MAX_BUFFERS_COUNT];
32
33
//+------------------+
34
//| PUBLIC FUNCTIONS |
35
//+==================+
36
37
106
size_t CIRC_getSpaceLeft(const circBuffer_t buffer)
38
{
39
106
    if(buffer == NULL)
40
    {
41
2
        return 0;
42
    }
43
44
104
    return buffer->info.size - CIRC_getNumberOfBytesInBuffer(buffer);
45
}
46
47
158
size_t CIRC_getNumberOfBytesInBuffer(const circBuffer_t buffer)
48
{
49
158
    if(buffer == NULL)
50
    {
51
2
        return 0;
52
    }
53
54
156
    size_t head = buffer->info.head;
55
56
156
    if(buffer->info.full)
57
    {
58
14
        return buffer->info.size;
59
    }
60
    else
61
    {
62
142
        return (head >= buffer->info.tail) ?
63
130
               (head - buffer->info.tail)
64
272
               : (head + (buffer->info.size - buffer->info.tail));
65
    }
66
}
67
68
90
volatile struct circ *CIRC_init(uint8_t *const dataSpace, size_t dataSize)
69
{
70

90
    if(dataSpace == NULL || dataSize == 0)
71
    {
72
6
        return NULL;
73
    }
74
75
84
    volatile struct circ *buff = buffers;
76
77
84
    volatile struct circ *newBuff = NULL;
78
79
412
    for(size_t i = 0; i < NELEMS(buffers); i++, buff++)
80
    {
81

330
        if(newBuff == NULL && buff->info.size == 0)
82
        {
83
78
            newBuff = buff;
84
        }
85
86

330
        if(buff->info.size > 0 && buff->data == dataSpace)
87
        {
88
2
            return NULL;
89
        }
90
    }
91
92
82
    if(newBuff == NULL)
93
    {
94
4
        return NULL;
95
    }
96
97
78
    newBuff->info.size = dataSize;
98
78
    newBuff->info.head = buff->info.tail = 0;
99
78
    newBuff->info.full = false;
100
78
    newBuff->data = dataSpace;
101
78
    return newBuff;
102
}
103
104
50
size_t CIRC_read(circBuffer_t buffer, uint8_t *dest, size_t size)
105
{
106

50
    if(buffer == NULL || dest == NULL || size == 0)
107
    {
108
6
        return 0;
109
    }
110
111
44
    size_t bytesAvailable = CIRC_getNumberOfBytesInBuffer(buffer);
112
113
44
    if(bytesAvailable == 0)
114
    {
115
2
        return 0;
116
    }
117
118
42
    if(size == 1)
119
    {
120
18
        *dest = buffer->data[buffer->info.tail];
121
18
        buffer->info.tail = (buffer->info.tail + 1) % buffer->info.size;
122
18
        buffer->info.full = false;
123
18
        return 1;
124
    }
125
126
24
    if(size > bytesAvailable)
127
    {
128
2
        size = bytesAvailable;
129
    }
130
131
24
    size_t tailAfterRead = buffer->info.tail + size;
132
24
    size_t firstChunkSize = size;
133
134
24
    if(tailAfterRead >= buffer->info.size)
135
    {
136
6
        firstChunkSize = buffer->info.size - buffer->info.tail;
137
6
        tailAfterRead = 0;
138
    }
139
140
24
    memcpy(dest, &buffer->data[buffer->info.tail], firstChunkSize);
141
24
    buffer->info.tail = tailAfterRead;
142
24
    size_t secondChunkSize = size - firstChunkSize;
143
144
24
    if(secondChunkSize)
145
    {
146
4
        memcpy(&dest[firstChunkSize], &buffer->data[buffer->info.tail],
147
               secondChunkSize);
148
4
        buffer->info.tail = secondChunkSize;
149
    }
150
151
24
    buffer->info.full = false;
152
24
    return size;
153
}
154
155
86
size_t CIRC_write(circBuffer_t buffer, uint8_t *src, size_t size)
156
{
157


86
    if(buffer == NULL || src == NULL || size == 0 || buffer->info.full)
158
    {
159
8
        return 0;
160
    }
161
162
78
    size_t spaceLeft = CIRC_getSpaceLeft(buffer);
163
164
78
    if(size >= spaceLeft)
165
    {
166
22
        size = spaceLeft;
167
22
        buffer->info.full = true;
168
    }
169
170
78
    if(size == 1)
171
    {
172
20
        buffer->data[buffer->info.head] = *src;
173
20
        buffer->info.head = (buffer->info.head + 1) % buffer->info.size;
174
20
        return 1;
175
    }
176
177
58
    size_t headAfterWrite = buffer->info.head + size;
178
58
    size_t firstChunkSize = size;
179
180
58
    if(headAfterWrite >= buffer->info.size)
181
    {
182
24
        firstChunkSize = buffer->info.size - buffer->info.head;
183
24
        headAfterWrite = 0;
184
    }
185
186
58
    memcpy(&buffer->data[buffer->info.head], src, firstChunkSize);
187
58
    buffer->info.head = headAfterWrite;
188
58
    size_t secondChunkSize = size - firstChunkSize;
189
190
58
    if(secondChunkSize)
191
    {
192
8
        memcpy(&buffer->data[buffer->info.head], &src[firstChunkSize],
193
               secondChunkSize);
194
8
        buffer->info.head = secondChunkSize;
195
    }
196
197
58
    return size;
198
}
199
200
8
size_t CIRC_getSize(const circBuffer_t buffer)
201
{
202
8
    if(buffer == NULL)
203
    {
204
2
        return 0;
205
    }
206
207
6
    return buffer->info.size;
208
}
209
210
10
bool CIRC_isFull(const circBuffer_t buffer)
211
{
212
10
    if(buffer == NULL)
213
    {
214
2
        return 0;
215
    }
216
217
8
    return buffer->info.full == true;
218
}
219
220
221
//+---------------------+
222
//| ONLY FOR UNIT TESTS |
223
//+=====================+
224
225
#ifdef TEST
226
88
void CIRC_deinit(void)
227
{
228
88
    memset((void *)buffers, 0, sizeof(buffers));
229
88
}
230
#endif
231
232
//+-------------------+
233
//| PRIVATE FUNCTIONS |
234
//+===================+
235