Skip to content

Commit d391353

Browse files
committedJul 21, 2020
Add serial util; move to github workflows
1 parent b4eb524 commit d391353

21 files changed

+426
-75
lines changed
 

‎.github/workflows/build-ci.yml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright (c) 2020 Siddharth Chandrasekaran <siddharth@embedjournal.com>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
name: Build CI
5+
6+
on:
7+
push:
8+
branches: [ master ]
9+
pull_request:
10+
branches: [ master ]
11+
12+
jobs:
13+
build:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@v2
18+
- name: configure
19+
run: cmake .
20+
- name: make
21+
run: make
22+
- name: make check
23+
run: make check

‎.travis.yml

-16
This file was deleted.

‎CMakeLists.txt

+29-38
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,40 @@
1-
cmake_minimum_required(VERSION 2.6)
2-
project(CUtils)
1+
#
2+
# Copyright (c) 2019 Siddharth Chandrasekaran <siddharth@embedjournal.com>
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
36

4-
set(CUTILS_VERSION_MAJOR 1)
5-
set(CUTILS_VERSION_MINOR 0)
7+
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
8+
project(CUtils VERSION 0.1.0 LANGUAGES C)
69

710
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
811
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
912
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
1013

11-
include_directories(${PROJECT_SOURCE_DIR}/src)
12-
include_directories(${PROJECT_SOURCE_DIR}/test)
14+
# Public headers
15+
include_directories(${CMAKE_SOURCE_DIR}/include)
1316

14-
set(TEST_DIR ${PROJECT_SOURCE_DIR}/test)
15-
set(SRC_DIR ${PROJECT_SOURCE_DIR}/src)
16-
set(SAMPLE_DIR ${PROJECT_SOURCE_DIR}/sample)
17-
18-
# Samples
19-
20-
## circular Buffers
21-
set(SAMPLE_SRC
22-
${SRC_DIR}/circbuf.c
23-
${SAMPLE_DIR}/sample-circbuf.c
17+
# libutils.a
18+
set(LIB_UTILS utils)
19+
file(GLOB LIB_UTILS_SRC ${CMAKE_SOURCE_DIR}/src/*.c)
20+
file(GLOB LIB_UTILS_INC ${CMAKE_SOURCE_DIR}/include/utils/*.h)
21+
add_library(${LIB_UTILS} STATIC ${LIB_UTILS_SRC})
22+
set_target_properties(${LIB_UTILS} PROPERTIES
23+
PUBLIC_HEADER "${LIB_UTILS_INC}"
2424
)
25-
add_executable(sample_circbuf ${SAMPLE_SRC})
26-
27-
## String
28-
set(SAMPLE_SRC
29-
${SRC_DIR}/strlib.c
30-
${SAMPLE_DIR}/sample-strlib.c
25+
install(
26+
TARGETS ${LIB_UTILS}
27+
DESTINATION ${CMAKE_INSTALL_DIR}/lib
28+
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_DIR}/include/utils/
3129
)
32-
add_executable(sample_strlib ${SAMPLE_SRC})
33-
34-
35-
# Tests
3630

37-
set(MOD_SRC
38-
${SRC_DIR}/circbuf.c
39-
${SRC_DIR}/strlib.c
31+
# check target
32+
set(TEST_BIN test-utils)
33+
file(GLOB TEST_SRC ${CMAKE_SOURCE_DIR}/test/*.c)
34+
add_executable(${TEST_BIN} ${TEST_SRC})
35+
target_link_libraries(${TEST_BIN} ${LIB_UTILS})
36+
add_custom_target(check
37+
COMMAND ${CMAKE_BINARY_DIR}/bin/${TEST_BIN}
38+
COMMAND rm ${CMAKE_BINARY_DIR}/bin/${TEST_BIN}
39+
DEPENDS ${TEST_BIN}
4040
)
41-
42-
set(TEST_SRC
43-
${TEST_DIR}/test.c
44-
${TEST_DIR}/test-circbuf.c
45-
${TEST_DIR}/test-strlib.c
46-
)
47-
48-
add_executable(test_cutils ${TEST_SRC} ${MOD_SRC})
49-

‎README.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# c-utils
2-
[![Build Status](https://travis-ci.com/EmbedJournal/c-utils.svg?branch=master)](https://travis-ci.com/EmbedJournal/c-utils)
2+
[![Build CI][1]][2]
33

44
This repository hosts some modular, drop-in, C utilities that you can copy into
55
your project and and kick-start your work.
@@ -8,8 +8,7 @@ your project and and kick-start your work.
88

99
The following methods/utils are available in this repo:
1010

11-
* Circular Buffers - A data-type agnostic circular buffer implementation read
12-
more [here][1].
11+
* Circular Buffers - A data-type agnostic circular buffer implementation read more [here][3].
1312
* Hexdump - A `hexdump -c` output equivalent method to inspect buffers.
1413
* String Library - A string library for some common use cases where pasing
1514
char pointer, and length around looks ugly.
@@ -19,5 +18,6 @@ The following methods/utils are available in this repo:
1918
You can clone this repo and copy individual files from src/ and link it to your
2019
project.
2120

22-
[1]: https://embedjournal.com/implementing-circular-buffer-embedded-c/
23-
21+
[1]: https://github.com/embedjournal/c-utils/workflows/Build%20CI/badge.svg
22+
[2]: https://github.com/embedjournal/c-utils/actions?query=workflow%3A%22Build+CI%22
23+
[3]: https://embedjournal.com/implementing-circular-buffer-embedded-c/
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

‎include/utils/serial.h

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) 2019 Siddharth Chandrasekaran <siddharth@embedjournal.com>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
*/
7+
8+
#ifndef _SERIAL_H_
9+
#define _SERIAL_H_
10+
11+
#ifdef __cplusplus
12+
extern "C" {
13+
#endif
14+
15+
#include <termios.h>
16+
17+
struct serial {
18+
int fd;
19+
struct termios new_termios;
20+
struct termios old_termios;
21+
};
22+
23+
struct serial *serial_open(const char *device, int baud, const char *mode);
24+
void serial_close(struct serial *ctx);
25+
int serial_read(struct serial *ctx, unsigned char *buf, int size);
26+
int serial_write(struct serial *ctx, unsigned char *buf, int size);
27+
void serial_flush_rx(struct serial *ctx);
28+
void serial_flush_tx(struct serial *ctx);
29+
void serial_flush(struct serial *ctx);
30+
31+
/* line control methods */
32+
int serial_get_dcd(struct serial *ctx);
33+
int serial_get_rng(struct serial *ctx);
34+
int serial_get_cts(struct serial *ctx);
35+
int serial_get_dsr(struct serial *ctx);
36+
void serial_assert_dtr(struct serial *ctx, int state);
37+
void serial_assert_rts(struct serial *ctx, int state);
38+
39+
#ifdef __cplusplus
40+
} /* extern "C" */
41+
#endif
42+
43+
#endif /* _SERIAL_H_ */
File renamed without changes.
File renamed without changes.

‎src/arg_parser.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include <string.h>
1111
#include <unistd.h>
1212

13-
#include "arg_parser.h"
13+
#include <utils/arg_parser.h>
1414

1515
#define is_lower_alpha(x) (x >= 97 && x <= 122)
1616

‎src/circbuf.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
#include <string.h>
88

9-
#include "circbuf.h"
9+
#include <utils/circbuf.h>
1010

1111
int __circ_gbuf_pop(circ_gbuf_t *circ_buf, void *elem, int read_only)
1212
{

‎src/hexdump.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@
66

77
#include <stdio.h>
88
#include <stdint.h>
9+
#include <ctype.h>
10+
11+
#include <utils/hexdump.h>
912

1013
void hexdump(const char *head, const uint8_t *data, size_t len)
1114
{
1215
int i;
1316
char str[16];
1417

15-
printf("%s [%d] =>\n 0000 %02x ", head, len, data[0]);
18+
printf("%s [%zu] =>\n 0000 %02x ", head, len, data[0]);
1619
str[0] = isprint(data[0]) ? data[0] : '.';
1720
for (i = 1; i < len; i++) {
1821
if ((i & 0x0f) == 0) {

‎src/procutils.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include <unistd.h>
1010
#include <fcntl.h>
1111

12-
#include "procutils.h"
12+
#include <utils/procutils.h>
1313

1414
int read_pid(const char *file, int *pid)
1515
{

‎src/serial.c

+301
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
/*
2+
* Copyright (c) 2019 Siddharth Chandrasekaran <siddharth@embedjournal.com>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
*/
7+
8+
/**
9+
* Note:
10+
* This code is based on Teunis van Beelen's implementation. Its API and coding
11+
* style needed a lot of work before consumption and hence warrented a full
12+
* rewrite. His implementation can be found at https://www.teuniz.net/RS-232/
13+
*
14+
* A good explanation can be found at https://www.cmrr.umn.edu/~strupp/serial.html
15+
*/
16+
17+
18+
#include <stdio.h>
19+
#include <string.h>
20+
#include <stdlib.h>
21+
22+
#include <termios.h>
23+
#include <sys/ioctl.h>
24+
#include <unistd.h>
25+
#include <fcntl.h>
26+
#include <sys/types.h>
27+
#include <sys/stat.h>
28+
#include <limits.h>
29+
#include <sys/file.h>
30+
#include <errno.h>
31+
32+
#include <utils/serial.h>
33+
34+
struct serial *serial_open(const char *device, int baud, const char *mode)
35+
{
36+
int status, tmp;
37+
int flow_control = 0, cflags = 0, ignore_parity = 0;
38+
struct serial *ctx;
39+
40+
switch (baud) {
41+
case 50: baud = B50; break;
42+
case 75: baud = B75; break;
43+
case 110: baud = B110; break;
44+
case 134: baud = B134; break;
45+
case 150: baud = B150; break;
46+
case 200: baud = B200; break;
47+
case 300: baud = B300; break;
48+
case 600: baud = B600; break;
49+
case 1200: baud = B1200; break;
50+
case 1800: baud = B1800; break;
51+
case 2400: baud = B2400; break;
52+
case 4800: baud = B4800; break;
53+
case 9600: baud = B9600; break;
54+
case 19200: baud = B19200; break;
55+
case 38400: baud = B38400; break;
56+
case 57600: baud = B57600; break;
57+
case 115200: baud = B115200; break;
58+
case 230400: baud = B230400; break;
59+
default:
60+
printf("invalid baudrate\n");
61+
return NULL;
62+
}
63+
64+
tmp = strlen(mode);
65+
if (tmp < 3 || tmp > 4) {
66+
printf("invalid mode \"%s\"\n", mode);
67+
return NULL;
68+
}
69+
70+
if (tmp == 4 && (mode[3] == 'F' || mode[3] == 'f'))
71+
flow_control = 1;
72+
73+
switch (mode[0]) {
74+
case '8': cflags |= CS8; break;
75+
case '7': cflags |= CS7; break;
76+
case '6': cflags |= CS6; break;
77+
case '5': cflags |= CS5; break;
78+
default:
79+
printf("invalid number of data-bits '%c'\n", mode[0]);
80+
return NULL;
81+
}
82+
83+
if (mode[1] == 'N' || mode[1] == 'n') { /* no parity */
84+
cflags |= IGNPAR;
85+
ignore_parity = 1;
86+
} else { /* has parity */
87+
cflags |= PARENB;
88+
if (mode[1] == 'O' || mode[1] == 'o')
89+
cflags |= PARODD;
90+
}
91+
92+
if (mode[2] == '2') {
93+
cflags |= CSTOPB;
94+
}
95+
96+
ctx = calloc(1, sizeof(struct serial));
97+
if (ctx == NULL) {
98+
printf("failed to alloc struct serial_port\n");
99+
return NULL;
100+
}
101+
102+
ctx->fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
103+
if (ctx->fd == -1) {
104+
perror("unable to open comport");
105+
goto error;
106+
}
107+
108+
if (flock(ctx->fd, LOCK_EX | LOCK_NB) != 0) {
109+
close(ctx->fd);
110+
perror("another process has locked the comport");
111+
goto error;
112+
}
113+
114+
if (tcgetattr(ctx->fd, &ctx->old_termios) == -1) {
115+
close(ctx->fd);
116+
perror("unable to read portsettings");
117+
goto error;
118+
}
119+
120+
ctx->new_termios.c_cflag = cflags | CLOCAL | CREAD;
121+
if (flow_control)
122+
ctx->new_termios.c_cflag |= CRTSCTS;
123+
ctx->new_termios.c_iflag = ignore_parity ? IGNPAR : INPCK;
124+
ctx->new_termios.c_oflag = 0;
125+
ctx->new_termios.c_lflag = 0;
126+
127+
/* block until n bytes are received */
128+
ctx->new_termios.c_cc[VMIN] = 0;
129+
130+
/* block until a timer expires (n * 100 mSec.) */
131+
ctx->new_termios.c_cc[VTIME] = 0;
132+
133+
cfsetispeed(&ctx->new_termios, baud);
134+
cfsetospeed(&ctx->new_termios, baud);
135+
136+
if (tcsetattr(ctx->fd, TCSANOW, &ctx->new_termios) == -1) {
137+
tcsetattr(ctx->fd, TCSANOW, &ctx->old_termios);
138+
close(ctx->fd);
139+
perror("unable to adjust portsettings");
140+
goto error;
141+
}
142+
143+
if (ioctl(ctx->fd, TIOCMGET, &status) == -1) {
144+
tcsetattr(ctx->fd, TCSANOW, &ctx->old_termios);
145+
perror("unable to get portstatus");
146+
goto error;
147+
}
148+
149+
status |= TIOCM_DTR; /* turn on DTR */
150+
status |= TIOCM_RTS; /* turn on RTS */
151+
152+
if (ioctl(ctx->fd, TIOCMSET, &status) == -1) {
153+
tcsetattr(ctx->fd, TCSANOW, &ctx->old_termios);
154+
perror("unable to set portstatus");
155+
goto error;
156+
}
157+
158+
return ctx;
159+
160+
error:
161+
if (ctx->fd != 0 && ctx->fd != -1)
162+
flock(ctx->fd, LOCK_UN);
163+
free(ctx);
164+
return NULL;
165+
}
166+
167+
void serial_close(struct serial *ctx)
168+
{
169+
int status;
170+
171+
if (ctx == NULL)
172+
return;
173+
174+
if (ioctl(ctx->fd, TIOCMGET, &status) == -1) {
175+
perror("unable to get portstatus");
176+
}
177+
178+
status &= ~TIOCM_DTR; /* turn off DTR */
179+
status &= ~TIOCM_RTS; /* turn off RTS */
180+
181+
if (ioctl(ctx->fd, TIOCMSET, &status) == -1) {
182+
perror("unable to set portstatus");
183+
}
184+
185+
tcsetattr(ctx->fd, TCSANOW, &ctx->old_termios);
186+
close(ctx->fd);
187+
flock(ctx->fd, LOCK_UN);
188+
189+
free(ctx);
190+
}
191+
192+
int serial_read(struct serial *ctx, unsigned char *buf, int size)
193+
{
194+
int n;
195+
196+
n = read(ctx->fd, buf, size);
197+
if (n < 0) {
198+
if (errno == EAGAIN)
199+
return 0;
200+
}
201+
return n;
202+
}
203+
204+
int serial_write(struct serial *ctx, unsigned char *buf, int size)
205+
{
206+
int n;
207+
208+
n = write(ctx->fd, buf, size);
209+
if (n < 0) {
210+
if (errno == EAGAIN)
211+
return 0;
212+
}
213+
return n;
214+
}
215+
216+
void serial_flush_rx(struct serial *ctx)
217+
{
218+
tcflush(ctx->fd, TCIFLUSH);
219+
}
220+
221+
void serial_flush_tx(struct serial *ctx)
222+
{
223+
tcflush(ctx->fd, TCOFLUSH);
224+
}
225+
226+
void serial_flush(struct serial *ctx)
227+
{
228+
tcflush(ctx->fd, TCIOFLUSH);
229+
}
230+
231+
int serial_get_dcd(struct serial *ctx)
232+
{
233+
int status;
234+
235+
ioctl(ctx->fd, TIOCMGET, &status);
236+
237+
return (status & TIOCM_CAR) ? 1 : 0;
238+
}
239+
240+
int serial_get_rng(struct serial *ctx)
241+
{
242+
int status;
243+
244+
ioctl(ctx->fd, TIOCMGET, &status);
245+
246+
return (status & TIOCM_RNG) ? 1 : 0;
247+
}
248+
249+
int serial_get_cts(struct serial *ctx)
250+
{
251+
int status;
252+
253+
ioctl(ctx->fd, TIOCMGET, &status);
254+
255+
return (status & TIOCM_CTS) ? 1 : 0;
256+
}
257+
258+
int serial_get_dsr(struct serial *ctx)
259+
{
260+
int status;
261+
262+
ioctl(ctx->fd, TIOCMGET, &status);
263+
264+
return (status & TIOCM_DSR) ? 1 : 0;
265+
}
266+
267+
void serial_assert_dtr(struct serial *ctx, int state)
268+
{
269+
int status;
270+
271+
if (ioctl(ctx->fd, TIOCMGET, &status) == -1) {
272+
perror("unable to get portstatus");
273+
}
274+
275+
if (state)
276+
status |= TIOCM_DTR; /* turn on RTS */
277+
else
278+
status &= ~TIOCM_DTR; /* turn off RTS */
279+
280+
if (ioctl(ctx->fd, TIOCMSET, &status) == -1) {
281+
perror("unable to set portstatus");
282+
}
283+
}
284+
285+
void serial_assert_rts(struct serial *ctx, int state)
286+
{
287+
int status;
288+
289+
if (ioctl(ctx->fd, TIOCMGET, &status) == -1) {
290+
perror("unable to get portstatus");
291+
}
292+
293+
if (state)
294+
status |= TIOCM_RTS; /* turn on RTS */
295+
else
296+
status &= ~TIOCM_RTS; /* turn off RTS */
297+
298+
if (ioctl(ctx->fd, TIOCMSET, &status) == -1) {
299+
perror("unable to set portstatus");
300+
}
301+
}

‎src/strlib.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
#include <stdio.h>
88
#include <stdarg.h>
99
#include <string.h>
10-
#include "strlib.h"
10+
11+
#include <utils/strlib.h>
1112

1213
int str_printf(string_t *s, const char *mode, const char *fmt, ...)
1314
{

‎src/strutils.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
* SPDX-License-Identifier: MIT
55
*/
66

7-
#include "strutils.h"
7+
#include <stdlib.h>
8+
9+
#include <utils/strutils.h>
810

911
static inline int hex2int(char ch)
1012
{

‎test/test-circbuf.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
#include <stdlib.h>
33
#include <time.h>
44

5+
#include <utils/circbuf.h>
6+
57
#include "test.h"
6-
#include "circbuf.h"
78

89
struct test_struct {
910
int a;
@@ -99,6 +100,6 @@ void do_test_circular_buffer(test_result_t *result)
99100
if (test_boundary() == 0) pass++; total++;
100101
if (test_probabilistic() == 0) pass++; total++;
101102

102-
result->pass += pass;
103-
result->total += total;
103+
result->pass = pass;
104+
result->total = total;
104105
}

‎test/test-strlib.c

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
#include <stdio.h>
22
#include <stdlib.h>
33
#include <time.h>
4+
#include <string.h>
5+
6+
#include <utils/strlib.h>
47

58
#include "test.h"
6-
#include "strlib.h"
79

810
GLOBAL_STRING_DEF(test_str, 8);
911

10-
int test_print_info_string(const char *msg, string_t *s)
12+
void test_print_info_string(const char *msg, string_t *s)
1113
{
12-
printf("\t[%s] s->len: %d s->max_len: %d s->buf: %s\n",
14+
printf("\t[%s] s->len: %zu s->max_len: %zu s->buf: %s\n",
1315
msg, s->len, s->max_len, s->buf);
1416
}
1517

@@ -86,6 +88,6 @@ void do_test_strlib(test_result_t *result)
8688
if (test_str_copy() == 0) pass++; total++;
8789
if (test_str_printf() == 0) pass++; total++;
8890

89-
result->pass += pass;
90-
result->total += total;
91+
result->pass = pass;
92+
result->total = total;
9193
}

‎test/test.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ void test_execute(test_t *t, test_module_t *tm)
2525
printf("Testing '%s'\n", tm->name);
2626
tm->runner(&result);
2727
mod_printf("Result: name:'%s' total:%d pass:%d\n",
28-
tm->name, result.total, result.pass);
28+
tm->name, result.total, result.pass);
2929
t->pass += result.pass;
3030
t->total += result.total;
3131
}
@@ -36,7 +36,7 @@ char *time_string(time_t *t)
3636
return date_time;
3737
}
3838

39-
int main(char *argc, char *argv[])
39+
int main(int argc, char *argv[])
4040
{
4141
int i=0, total_pass, total_exec;
4242
time_t start_time, end_time;

0 commit comments

Comments
 (0)
Please sign in to comment.