-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcanlib.go
355 lines (311 loc) · 17.2 KB
/
canlib.go
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
package gocanlib
// #cgo LDFLAGS: -lcanlib32
// #include <canlib.h>
import "C"
import (
"fmt"
"unsafe"
)
type CANMessage struct {
Identifier int32
Data []byte
DLC uint32
Flags uint32
Timestamp uint32
}
func InitializeLibrary() error {
C.canInitializeLibrary()
return nil
}
func UnloadLibrary() error {
return NewError(C.canUnloadLibrary())
}
func GetNumberOfChannels() (int, error) {
noChannels := C.int(0)
status := C.canGetNumberOfChannels(&noChannels)
return int(noChannels), NewError(status)
}
type ChannelDataItem int
const (
CHANNELDATA_CHANNEL_CAP ChannelDataItem = C.canCHANNELDATA_CHANNEL_CAP
CHANNELDATA_TRANS_CAP ChannelDataItem = C.canCHANNELDATA_TRANS_CAP
CHANNELDATA_CHANNEL_FLAGS ChannelDataItem = C.canCHANNELDATA_CHANNEL_FLAGS
CHANNELDATA_CARD_TYPE ChannelDataItem = C.canCHANNELDATA_CARD_TYPE
CHANNELDATA_CARD_NUMBER ChannelDataItem = C.canCHANNELDATA_CARD_NUMBER
CHANNELDATA_CHAN_NO_ON_CARD ChannelDataItem = C.canCHANNELDATA_CHAN_NO_ON_CARD
CHANNELDATA_CARD_SERIAL_NO ChannelDataItem = C.canCHANNELDATA_CARD_SERIAL_NO
CHANNELDATA_TRANS_SERIAL_NO ChannelDataItem = C.canCHANNELDATA_TRANS_SERIAL_NO
CHANNELDATA_CARD_FIRMWARE_REV ChannelDataItem = C.canCHANNELDATA_CARD_FIRMWARE_REV
CHANNELDATA_CARD_HARDWARE_REV ChannelDataItem = C.canCHANNELDATA_CARD_HARDWARE_REV
CHANNELDATA_CARD_UPC_NO ChannelDataItem = C.canCHANNELDATA_CARD_UPC_NO
CHANNELDATA_TRANS_UPC_NO ChannelDataItem = C.canCHANNELDATA_TRANS_UPC_NO
CHANNELDATA_CHANNEL_NAME ChannelDataItem = C.canCHANNELDATA_CHANNEL_NAME
CHANNELDATA_DLL_FILE_VERSION ChannelDataItem = C.canCHANNELDATA_DLL_FILE_VERSION
CHANNELDATA_DLL_PRODUCT_VERSION ChannelDataItem = C.canCHANNELDATA_DLL_PRODUCT_VERSION
CHANNELDATA_DLL_FILETYPE ChannelDataItem = C.canCHANNELDATA_DLL_FILETYPE
CHANNELDATA_TRANS_TYPE ChannelDataItem = C.canCHANNELDATA_TRANS_TYPE
CHANNELDATA_DEVICE_PHYSICAL_POSITION ChannelDataItem = C.canCHANNELDATA_DEVICE_PHYSICAL_POSITION
CHANNELDATA_UI_NUMBER ChannelDataItem = C.canCHANNELDATA_UI_NUMBER
CHANNELDATA_TIMESYNC_ENABLED ChannelDataItem = C.canCHANNELDATA_TIMESYNC_ENABLED
CHANNELDATA_DRIVER_FILE_VERSION ChannelDataItem = C.canCHANNELDATA_DRIVER_FILE_VERSION
CHANNELDATA_DRIVER_PRODUCT_VERSION ChannelDataItem = C.canCHANNELDATA_DRIVER_PRODUCT_VERSION
CHANNELDATA_MFGNAME_UNICODE ChannelDataItem = C.canCHANNELDATA_MFGNAME_UNICODE
CHANNELDATA_MFGNAME_ASCII ChannelDataItem = C.canCHANNELDATA_MFGNAME_ASCII
CHANNELDATA_DEVDESCR_UNICODE ChannelDataItem = C.canCHANNELDATA_DEVDESCR_UNICODE
CHANNELDATA_DEVDESCR_ASCII ChannelDataItem = C.canCHANNELDATA_DEVDESCR_ASCII
CHANNELDATA_DRIVER_NAME ChannelDataItem = C.canCHANNELDATA_DRIVER_NAME
CHANNELDATA_CHANNEL_QUALITY ChannelDataItem = C.canCHANNELDATA_CHANNEL_QUALITY
CHANNELDATA_ROUNDTRIP_TIME ChannelDataItem = C.canCHANNELDATA_ROUNDTRIP_TIME
CHANNELDATA_BUS_TYPE ChannelDataItem = C.canCHANNELDATA_BUS_TYPE
CHANNELDATA_DEVNAME_ASCII ChannelDataItem = C.canCHANNELDATA_DEVNAME_ASCII
CHANNELDATA_TIME_SINCE_LAST_SEEN ChannelDataItem = C.canCHANNELDATA_TIME_SINCE_LAST_SEEN
CHANNELDATA_REMOTE_OPERATIONAL_MODE ChannelDataItem = C.canCHANNELDATA_REMOTE_OPERATIONAL_MODE
CHANNELDATA_REMOTE_PROFILE_NAME ChannelDataItem = C.canCHANNELDATA_REMOTE_PROFILE_NAME
CHANNELDATA_REMOTE_HOST_NAME ChannelDataItem = C.canCHANNELDATA_REMOTE_HOST_NAME
CHANNELDATA_REMOTE_MAC ChannelDataItem = C.canCHANNELDATA_REMOTE_MAC
CHANNELDATA_MAX_BITRATE ChannelDataItem = C.canCHANNELDATA_MAX_BITRATE
CHANNELDATA_CHANNEL_CAP_MASK ChannelDataItem = C.canCHANNELDATA_CHANNEL_CAP_MASK
CHANNELDATA_CUST_CHANNEL_NAME ChannelDataItem = C.canCHANNELDATA_CUST_CHANNEL_NAME
CHANNELDATA_IS_REMOTE ChannelDataItem = C.canCHANNELDATA_IS_REMOTE
CHANNELDATA_REMOTE_TYPE ChannelDataItem = C.canCHANNELDATA_REMOTE_TYPE
CHANNELDATA_LOGGER_TYPE ChannelDataItem = C.canCHANNELDATA_LOGGER_TYPE
CHANNELDATA_HW_STATUS ChannelDataItem = C.canCHANNELDATA_HW_STATUS
CHANNELDATA_FEATURE_EAN ChannelDataItem = C.canCHANNELDATA_FEATURE_EAN
CHANNELDATA_BUS_PARAM_LIMITS ChannelDataItem = C.canCHANNELDATA_BUS_PARAM_LIMITS
CHANNELDATA_CLOCK_INFO ChannelDataItem = C.canCHANNELDATA_CLOCK_INFO
CHANNELDATA_CHANNEL_CAP_EX ChannelDataItem = C.canCHANNELDATA_CHANNEL_CAP_EX
)
// This function can be used to retrieve certain pieces of information about a channel.
func GetChannelDataString(channel int, item ChannelDataItem) (string, error) {
msg := make([]byte, 256)
err := NewError(C.canGetChannelData(C.int(channel), C.int(item), unsafe.Pointer(&msg[0]), C.size_t(len(msg))))
if err != nil {
return "", err
}
return C.GoString((*C.char)(unsafe.Pointer(&msg[0]))), nil
}
func GetChannelByte(channel int, item ChannelDataItem) ([]byte, error) {
msg := make([]byte, 256)
status := C.canGetChannelData(C.int(channel), C.int(item), unsafe.Pointer(&msg[0]), C.size_t(len(msg)))
if err := NewError(status); err != nil {
return nil, err
}
return msg, nil
}
type OpenFlag int
const (
OPEN_EXCLUSIVE OpenFlag = C.canOPEN_EXCLUSIVE // Exclusive access
OPEN_REQUIRE_EXTENDED OpenFlag = C.canOPEN_REQUIRE_EXTENDED // Fail if can't use extended mode
OPEN_ACCEPT_VIRTUAL OpenFlag = C.canOPEN_ACCEPT_VIRTUAL // Allow use of virtual CAN
OPEN_OVERRIDE_EXCLUSIVE OpenFlag = C.canOPEN_OVERRIDE_EXCLUSIVE // Open, even if in exclusive access
OPEN_REQUIRE_INIT_ACCESS OpenFlag = C.canOPEN_REQUIRE_INIT_ACCESS // Init access to bus
OPEN_NO_INIT_ACCESS OpenFlag = C.canOPEN_NO_INIT_ACCESS
OPEN_ACCEPT_LARGE_DLC OpenFlag = C.canOPEN_ACCEPT_LARGE_DLC
OPEN_CAN_FD OpenFlag = C.canOPEN_CAN_FD
OPEN_CAN_FD_NONISO OpenFlag = C.canOPEN_CAN_FD_NONISO
OPEN_INTERNAL_L OpenFlag = C.canOPEN_INTERNAL_L
)
// Opens a CAN channel (circuit) and returns a handle which is used in subsequent calls to CANlib.
func OpenChannel(channel int, flags OpenFlag) (Handle, error) {
handle := C.canOpenChannel(C.int(channel), C.int(flags))
return Handle(handle), NewError(handle)
}
// This API call returns the version of the CANlib API DLL (canlib32.dll).
func GetVersion() string {
version := C.canGetVersion()
return fmt.Sprintf("%d.%d", version>>8, version&0xFF)
}
// Handle is a handle to a CAN channel (circuit).
type Handle C.int
type AcceptFlag uint
const (
FILTER_ACCEPT AcceptFlag = C.canFILTER_ACCEPT
FILTER_REJECT AcceptFlag = C.canFILTER_REJECT
FILTER_SET_CODE_STD AcceptFlag = C.canFILTER_SET_CODE_STD
FILTER_SET_MASK_STD AcceptFlag = C.canFILTER_SET_MASK_STD
FILTER_SET_CODE_EXT AcceptFlag = C.canFILTER_SET_CODE_EXT
FILTER_SET_MASK_EXT AcceptFlag = C.canFILTER_SET_MASK_EXT
FILTER_NULL_MASK AcceptFlag = C.canFILTER_NULL_MASK
)
// This routine sets the message acceptance filters on a CAN channel.
// On some boards the acceptance filtering is done by the CAN hardware; on other boards (typically those with an embedded CPU,) the acceptance filtering is done by software. canAccept() behaves in the same way for all boards, however.
// SetAcceptanceFilter() and Accept() both serve the same purpose but the former can set the code and mask in just one call.
// If you want to remove a filter, call canAccept() with the mask set to 0.
func (hnd Handle) Accept(envelope int, flag AcceptFlag) error {
status := C.canAccept(C.int(hnd), C.long(envelope), C.uint(flag))
return NewError(status)
}
// Closes the channel associated with the handle. If no other threads are using the CAN circuit, it is taken off bus. The handle can not be used for further references to the channel, so any variable containing it should be zeroed.
// Close() will almost always return canOK; the specified handle is closed on an best-effort basis.
func (hnd Handle) Close() error {
status := C.canClose(C.int(hnd))
hnd = -1
return NewError(status)
}
// Takes the specified channel on-bus.
// If you are using multiple handles to the same physical channel, for example if you are writing a threaded application, you must call canBusOn() once for each handle. The same applies to canBusOff() - the physical channel will not go off bus until the last handle to the channel goes off bus.
func (hnd Handle) BusOn() error {
return NewError(C.canBusOn(C.int(hnd)))
}
// Takes the specified handle off-bus. If no other handle is active on the same channel, the channel will also be taken off-bus
func (hnd Handle) BusOff() error {
return NewError(C.canBusOff(C.int(hnd)))
}
// This function removes all received messages from the handle's receive queue. Other handles open to the same channel are not affected by this operation. That is, only the messages belonging to the handle you are passing to canFlushReceiveQueue are discarded.
func (hnd Handle) FlushReceiveQueue() error {
return NewError(C.canFlushReceiveQueue(C.int(hnd)))
}
// This function removes all messages pending transmission from the transmit queue of the circuit.
func (hnd Handle) FlushTransmitQueue() error {
return NewError(C.canFlushTransmitQueue(C.int(hnd)))
}
// Allocates an object buffer associated with a handle to a CAN circuit.
func (hnd Handle) ObjBufAllocate(typ int) (int, error) {
idx := C.canObjBufAllocate(C.int(hnd), C.int(typ))
if idx < 0 {
return -1, NewError(idx)
}
return int(idx), nil
}
type MsgFlag uint32
const (
MSG_MASK MsgFlag = C.canMSG_MASK
MSG_RTR MsgFlag = C.canMSG_RTR
MSG_STD MsgFlag = C.canMSG_STD
MSG_EXT MsgFlag = C.canMSG_EXT
MSG_WAKEUP MsgFlag = C.canMSG_WAKEUP
MSG_NERR MsgFlag = C.canMSG_NERR
MSG_ERROR_FRAME MsgFlag = C.canMSG_ERROR_FRAME
MSG_TXACK MsgFlag = C.canMSG_TXACK
MSG_TXRQ MsgFlag = C.canMSG_TXRQ
MSG_DELAY_MSG MsgFlag = C.canMSG_DELAY_MSG
MSG_LOCAL_TXACK MsgFlag = C.canMSG_LOCAL_TXACK
MSG_SINGLE_SHOT MsgFlag = C.canMSG_SINGLE_SHOT
MSG_TXNACK MsgFlag = C.canMSG_TXNACK
MSG_ABL MsgFlag = C.canMSG_ABL
FDMSG_MASK MsgFlag = C.canFDMSG_MASK
FDMSG_EDL MsgFlag = C.canFDMSG_EDL
FDMSG_FDF MsgFlag = C.canFDMSG_FDF
FDMSG_BRS MsgFlag = C.canFDMSG_BRS
FDMSG_ESI MsgFlag = C.canFDMSG_ESI
)
func (hnd Handle) ObjBufWrite(idx, id int, message []byte, flags MsgFlag) error {
return NewError(C.canObjBufWrite(C.int(hnd), C.int(idx), C.int(id), unsafe.Pointer(&message[0]), C.uint(len(message)), C.uint(flags)))
}
// This function tries to reset a CAN bus controller by taking the channel off bus and then on bus again (if it was on bus before the call to canResetBus().)
// This function will affect the hardware (and cause a real reset of the CAN chip) only if hnd is the only handle open on the channel. If there are other open handles, this operation will not affect the hardware.
func (hnd Handle) ResetBus() error {
return NewError(C.canResetBus(C.int(hnd)))
}
type BusParamsFreq int
const (
BITRATE_1M BusParamsFreq = C.canBITRATE_1M
BITRATE_500K BusParamsFreq = C.canBITRATE_500K
BITRATE_250K BusParamsFreq = C.canBITRATE_250K
BITRATE_125K BusParamsFreq = C.canBITRATE_125K
BITRATE_100K BusParamsFreq = C.canBITRATE_100K
BITRATE_62K BusParamsFreq = C.canBITRATE_62K
BITRATE_50K BusParamsFreq = C.canBITRATE_50K
BITRATE_83K BusParamsFreq = C.canBITRATE_83K
BITRATE_10K BusParamsFreq = C.canBITRATE_10K
)
// This routine sets the message acceptance filters on a CAN channel.
//
// Format of code and mask:
//
// - A binary 1 in a mask means "the corresponding bit in the code is relevant"
// - A binary 0 in a mask means "the corresponding bit in the code is not relevant"
// - A relevant binary 1 in a code means "the corresponding bit in the identifier must be 1"
// - A relevant binary 0 in a code means "the corresponding bit in the identifier must be 0"
//
// In other words, the message is accepted if ((code XOR id) AND mask) == 0.
//
// extended should be set to:
//
// 0. (FALSE): if the code and mask shall apply to 11-bit CAN identifiers.
// 1. (TRUE): if the code and mask shall apply to 29-bit CAN identifiers.
//
// If you want to remove a filter, call canSetAcceptanceFilter() with the mask set to 0.
//
// On some boards the acceptance filtering is done by the CAN hardware; on other boards (typically those with an embedded CPU,) the acceptance filtering is done by software. canSetAcceptanceFilter() behaves in the same way for all boards, however.
// canSetAcceptanceFilter() and canAccept() both serve the same purpose but the former can set the code and mask in just one call.
func (hnd Handle) SetAcceptanceFilter(code, mask uint, extended bool) error {
var ext int
if extended {
ext = 1
} else {
ext = 0
}
return NewError(C.canSetAcceptanceFilter(C.int(hnd), C.uint(code), C.uint(mask), C.int(ext)))
}
// The canSetBitrate() function sets the nominal bit rate of the specified CAN channel. The sampling point is recalculated and kept as close as possible to the value before the call.
//
// Parameters:
//
// [bitrate] bitrate The new bit rate, in bits/second.
func (hnd Handle) SetBitrate(bitrate int) error {
return NewError(C.canSetBitrate(C.int(hnd), C.int(bitrate)))
}
// This function sets the nominal bus timing parameters for the specified CAN controller.
// The library provides default values for tseg1, tseg2, sjw and noSamp when freq is specified to one of the pre-defined constants, canBITRATE_xxx for classic CAN and canFD_BITRATE_xxx for CAN FD.
// If freq is any other value, no default values are supplied by the library.
// If you are using multiple handles to the same physical channel, for example if you are writing a threaded application, you must call canBusOff() once for each handle. The same applies to canBusOn() - the physical channel will not go off bus until the last handle to the channel goes off bus.
func (hnd Handle) SetBusParams(freq BusParamsFreq, tseg1, tseg2, sjw, noSamp, syncmode uint) error {
return NewError(C.canSetBusParams(C.int(hnd), C.long(freq), C.uint(tseg1), C.uint(tseg2), C.uint(sjw), C.uint(noSamp), C.uint(syncmode)))
}
// This function sets the bus timing parameters using the same convention as the 82c200 CAN controller (which is the same as many other CAN controllers, for example, the 82527.)
// To calculate the bit timing parameters, you can use the bit timing calculator that is included with CANlib SDK. Look in the BIN directory.
func (hnd Handle) SetBusParamsC200(btr0, btr1 uint8) error {
return NewError(C.canSetBusParamsC200(C.int(hnd), C.uchar(btr0), C.uchar(btr1)))
}
type DriverType uint
const (
DRIVER_NORMAL DriverType = C.canDRIVER_NORMAL
DRIVER_SILENT DriverType = C.canDRIVER_SILENT
DRIVER_SELFRECEPTION DriverType = C.canDRIVER_SELFRECEPTION
DRIVER_OFF DriverType = C.canDRIVER_OFF
)
// This function sets the driver type for a CAN controller.
// This corresponds loosely to the bus output control register in the CAN controller, hence the name of this function.
// CANlib does not allow for direct manipulation of the bus output control register; instead, symbolic constants are used to select the desired driver type.
func SetBusOutputControl(hnd Handle, drivertype DriverType) error {
return NewError(C.canSetBusOutputControl(C.int(hnd), C.uint(drivertype)))
}
// Reads the error counters of the CAN controller
//
// returns: tx error counter, rx error counter, overrun error counter
func (hnd Handle) ReadErrorCounters() (uint, uint, uint, error) {
var tec, rec, ovr C.uint
status := C.canReadErrorCounters(C.int(hnd), &tec, &rec, &ovr)
return uint(tec), uint(rec), uint(ovr), NewError(status)
}
// Reads a message from the receive buffer. If no message is available, the function waits until a message arrives or a timeout occurs.
func (hnd Handle) ReadWait(timeout uint32) (*CANMessage, error) {
msg := new(CANMessage)
msg.Data = make([]byte, 64)
status := C.canReadWait(
C.int(hnd),
(*C.long)(&msg.Identifier), // Cast uint32 pointer to *C.long
unsafe.Pointer(&msg.Data[0]), // This one is correct as is
(*C.uint)(&msg.DLC), // Cast uint32 pointer to *C.uint
(*C.uint)(&msg.Flags), // Cast uint32 pointer to *C.uint
(*C.ulong)(&msg.Timestamp), // Cast uint32 pointer to *C.ulong
C.ulong(timeout), // Cast timeout to C.ulong
)
if err := NewError(status); err != nil {
return nil, err
}
return msg, nil
}
// This function sends a CAN message. The call returns immediately after queuing the message to the driver so the message has not necessarily been transmitted.
func (hnd Handle) Write(identifier uint32, data []byte, flags MsgFlag) error {
return NewError(C.canWrite(C.int(hnd), C.long(identifier), unsafe.Pointer(&data[0]), C.uint(len(data)), C.uint(flags)))
}
// Waits until all CAN messages for the specified handle are sent, or the timeout period expires.
func (hnd Handle) WriteSync(timeoutMS int) error {
return NewError(C.canWriteSync(C.int(hnd), C.ulong(timeoutMS)))
}
// This function sends a CAN message and returns when the message has been successfully transmitted, or the timeout expires.
func (hnd Handle) WriteWait(identifier uint32, data []byte, flags MsgFlag, timeoutMS uint32) error {
return NewError(C.canWriteWait(C.int(hnd), C.long(identifier), unsafe.Pointer(&data[0]), C.uint(len(data)), C.uint(flags), C.ulong(timeoutMS)))
}