aboutsummaryrefslogtreecommitdiff
path: root/libvoltronic/voltronic_dev_serial_libserialport.c
blob: c3883465229d5d9de37705116caa01b0bb0af39f (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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/**
 * Copyright (C) 2019  Johan van der Vyver
 *
 * 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "voltronic_dev_impl.h"
#include "voltronic_dev_serial.h"
#include <libserialport.h>

#define VOLTRONIC_DEV_SP(_impl_ptr_) ((struct sp_port*) (_impl_ptr_))

static int voltronic_dev_serial_configure(
  struct sp_port* port,
  const baud_rate_t baud_rate,
  const data_bits_t data_bits,
  const stop_bits_t stop_bits,
  const serial_parity_t parity);

voltronic_dev_t voltronic_serial_create(
    const char* name,
    const baud_rate_t baud_rate,
    const data_bits_t data_bits,
    const stop_bits_t stop_bits,
    const serial_parity_t parity) {

  enum sp_return sp_result;
  struct sp_port* port = 0;
  if (name != 0) {
    struct sp_port* tmp_port = { 0 };
    SET_LAST_ERROR(0);
    if ((sp_result = sp_get_port_by_name(name, &tmp_port)) == SP_OK) {
      port = tmp_port;
    }
  }

  if (port != 0) {
    SET_LAST_ERROR(0);
    if ((sp_result = sp_open(port, SP_MODE_READ_WRITE)) == SP_OK) {
      SET_LAST_ERROR(0);
      if (voltronic_dev_serial_configure(port, baud_rate, data_bits, stop_bits, parity) > 0) {
        sp_flush(port, SP_BUF_BOTH);
        SET_LAST_ERROR(0);
        return voltronic_dev_internal_create((void*) port);
      }
    }

    const last_error_t last_error = GET_LAST_ERROR();
    sp_free_port(port);
    SET_LAST_ERROR(last_error);
  }

  return 0;
}

inline int voltronic_dev_impl_read(
    void* impl_ptr,
    char* buffer,
    const size_t buffer_size,
    const unsigned int timeout_milliseconds) {

  SET_LAST_ERROR(0);
  return (int) sp_blocking_read_next(
    VOLTRONIC_DEV_SP(impl_ptr),
    (void*) buffer,
    buffer_size,
    (unsigned int) timeout_milliseconds);
}

inline int voltronic_dev_impl_write(
    void* impl_ptr,
    const char* buffer,
    const size_t buffer_size,
    const unsigned int timeout_milliseconds) {

  SET_LAST_ERROR(0);
  return (int) sp_blocking_write(
    VOLTRONIC_DEV_SP(impl_ptr),
    (const void*) buffer,
    buffer_size,
    (unsigned int) timeout_milliseconds);
}

inline int voltronic_dev_impl_close(void* impl_ptr) {
  struct sp_port* sp_port = VOLTRONIC_DEV_SP(impl_ptr);
  SET_LAST_ERROR(0);
  const enum sp_return result = sp_close(sp_port);
  if (result == SP_OK) {
    sp_free_port(sp_port);
    return 1;
  } else {
    return 0;
  }
}

static inline int voltronic_dev_baud_rate(
  const baud_rate_t baud_rate) {

  return (int) baud_rate;
}

static inline int voltronic_dev_data_bits(
  const data_bits_t data_bits) {

  switch(data_bits){
    case DATA_BITS_FIVE: return 5;
    case DATA_BITS_SIX: return 6;
    case DATA_BITS_SEVEN: return 7;
    case DATA_BITS_EIGHT: return 8;
    default: return -1;
  }
}

static inline int voltronic_dev_stop_bits(
  const stop_bits_t stop_bits) {

  switch(stop_bits){
    case STOP_BITS_ONE: return 1;
    case STOP_BITS_TWO: return 2;
    case STOP_BITS_ONE_AND_ONE_HALF: return 3;
    default: return -1;
  }
}

static inline enum sp_parity voltronic_dev_serial_parity(
    const serial_parity_t parity) {

  switch(parity){
    case SERIAL_PARITY_NONE: return SP_PARITY_NONE;
    case SERIAL_PARITY_ODD: return SP_PARITY_ODD;
    case SERIAL_PARITY_EVEN: return SP_PARITY_EVEN;
    case SERIAL_PARITY_MARK: return SP_PARITY_MARK;
    case SERIAL_PARITY_SPACE: return SP_PARITY_SPACE;
    default: return SP_PARITY_INVALID;
  }
}

static int voltronic_dev_serial_configure(
  struct sp_port* port,
  const baud_rate_t baud_rate,
  const data_bits_t data_bits,
  const stop_bits_t stop_bits,
  const serial_parity_t parity) {

  const int sp_baud_rate = voltronic_dev_baud_rate(baud_rate);
  const int sp_data_bits = voltronic_dev_data_bits(data_bits);
  const int sp_stop_bits = voltronic_dev_stop_bits(stop_bits);
  const enum sp_parity sp_sp_parity = voltronic_dev_serial_parity(parity);

  if ((sp_data_bits == -1) ||
    (sp_data_bits == -1) ||
    (sp_stop_bits == -1) ||
    (sp_sp_parity == SP_PARITY_INVALID)) {

    SET_INVALID_INPUT();
    return 0;
  }

  int result = 0;
  struct sp_port_config *config;

  SET_LAST_ERROR(0);
  if (sp_new_config(&config) == SP_OK) {
    SET_LAST_ERROR(0);
    if (sp_get_config(port, config) == SP_OK) {
      SET_LAST_ERROR(0);
      if ((sp_set_config_baudrate (config, sp_baud_rate) == SP_OK) &&
        (sp_set_config_bits(config, sp_data_bits) == SP_OK) &&
        (sp_set_config_stopbits(config, sp_stop_bits) == SP_OK) &&
        (sp_set_config_parity(config, sp_sp_parity) == SP_OK)) {

        SET_LAST_ERROR(0);
        if (sp_set_config(port, config) == SP_OK) {
          result = 1;
        }
      }
    }

    const last_error_t last_error = GET_LAST_ERROR();
    sp_free_config(config);
    SET_LAST_ERROR(last_error);
  }

  return result;
}