355 lines
13 KiB
Go
355 lines
13 KiB
Go
package main
|
|
|
|
// #cgo CFLAGS: -I../../../include
|
|
// #cgo LDFLAGS: -L../../../build -licsneoc2
|
|
// #include "icsneo/icsneoc2.h"
|
|
// #include "stdint.h"
|
|
import "C"
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
"unsafe"
|
|
)
|
|
|
|
func main() {
|
|
// Find devices connected to host.
|
|
devices := [255]*C.icsneoc2_device_t{nil}
|
|
devicesCount := 255
|
|
print("Finding devices... ")
|
|
if res := C.icsneoc2_device_find_all(&devices[0], (*C.uint)(unsafe.Pointer(&devicesCount)), nil); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return
|
|
}
|
|
fmt.Printf("OK, %d device(s) found\n", devicesCount)
|
|
// List off the devices
|
|
for _, device := range devices[:devicesCount] {
|
|
// Get description of the device
|
|
description := make([]byte, 255)
|
|
descriptionLength := 255
|
|
if res := C.icsneoc2_device_description_get(device, (*C.char)(unsafe.Pointer(&description[0])), (*C.uint)(unsafe.Pointer(&descriptionLength))); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
continue
|
|
}
|
|
fmt.Printf("%s @ Handle %p\n", description, device)
|
|
// Get/Set open options
|
|
options := C.icsneoc2_open_options_none
|
|
if res := C.icsneoc2_device_open_options_get(device, (*C.icsneoc2_open_options_t)(unsafe.Pointer(&options))); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
continue
|
|
}
|
|
options &= ^C.icsneoc2_open_options_sync_rtc
|
|
options &= ^C.icsneoc2_open_options_go_online
|
|
fmt.Printf("\tDevice open options: 0x%X\n", options)
|
|
if res := C.icsneoc2_device_open_options_set(device, (C.icsneoc2_open_options_t)(options)); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
continue
|
|
}
|
|
// Open the device
|
|
fmt.Printf("\tOpening device: %s...\n", description)
|
|
if res := C.icsneoc2_device_open(device); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
continue
|
|
}
|
|
defer func() {
|
|
if !printDeviceEvents(device, string(description)) {
|
|
println("\tFailed to print events...")
|
|
}
|
|
fmt.Printf("\tClosing device: %s...\n", description)
|
|
if res := C.icsneoc2_device_close(device); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return
|
|
}
|
|
}()
|
|
// Get timestamp resolution of the device
|
|
fmt.Printf("\tGetting timestamp resolution... ")
|
|
var timestampResolution C.uint = 0
|
|
if res := C.icsneoc2_device_timestamp_resolution_get(device, ×tampResolution); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return
|
|
}
|
|
fmt.Printf("%dns\n", timestampResolution)
|
|
// Get baudrates for HSCAN
|
|
fmt.Printf("\tGetting HSCAN Baudrate... ")
|
|
var baudrate uint64 = 0
|
|
if res := C.icsneoc2_device_baudrate_get(device, (C.icsneoc2_netid_t)(C.icsneoc2_netid_hscan), (*C.uint64_t)(unsafe.Pointer(&baudrate))); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return
|
|
}
|
|
fmt.Printf("%dmbit/s\n", baudrate)
|
|
// Get FD baudrates for HSCAN
|
|
fmt.Printf("\tGetting FD HSCAN Baudrate... ")
|
|
var fdBaudrate uint64 = 0
|
|
if res := C.icsneoc2_device_canfd_baudrate_get(device, (C.icsneoc2_netid_t)(C.icsneoc2_netid_hscan), (*C.uint64_t)(unsafe.Pointer(&fdBaudrate))); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return
|
|
}
|
|
fmt.Printf("%dmbit/s\n", fdBaudrate)
|
|
// Set baudrates for HSCAN
|
|
// saveToDevice: If this is set to true, the baudrate will be saved on the device
|
|
// and will persist through a power cycle
|
|
var saveToDevice C.bool = false
|
|
fmt.Printf("\tSetting HSCAN Baudrate... ")
|
|
if res := C.icsneoc2_device_baudrate_set(device, (C.icsneoc2_netid_t)(C.icsneoc2_netid_hscan), (C.uint64_t)(baudrate), saveToDevice); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return
|
|
}
|
|
fmt.Printf("OK\n")
|
|
// Set FD baudrates for HSCAN
|
|
fmt.Printf("\tSetting FD HSCAN Baudrate... ")
|
|
if res := C.icsneoc2_device_canfd_baudrate_set(device, (C.icsneoc2_netid_t)(C.icsneoc2_netid_hscan), (C.uint64_t)(fdBaudrate), saveToDevice); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return
|
|
}
|
|
fmt.Printf("OK\n")
|
|
// Get RTC
|
|
fmt.Printf("\tGetting RTC... ")
|
|
var unix_epoch C.int64_t = 0
|
|
if res := C.icsneoc2_device_rtc_get(device, (*C.int64_t)(unsafe.Pointer(&unix_epoch))); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return
|
|
}
|
|
currentRTC := time.Unix(int64(unix_epoch), 0)
|
|
fmt.Printf("%d %s\n", currentRTC.Unix(), currentRTC)
|
|
// Set RTC
|
|
fmt.Printf("\tSetting RTC... ")
|
|
unix_epoch = (C.int64_t)(time.Now().Unix())
|
|
if res := C.icsneoc2_device_rtc_set(device, unix_epoch); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return
|
|
}
|
|
fmt.Printf("OK\n")
|
|
// Get RTC
|
|
fmt.Printf("\tGetting RTC... ")
|
|
if res := C.icsneoc2_device_rtc_get(device, (*C.int64_t)(unsafe.Pointer(&unix_epoch))); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return
|
|
}
|
|
currentRTC = time.Unix(int64(unix_epoch), 0)
|
|
fmt.Printf("%d %s\n", currentRTC.Unix(), currentRTC)
|
|
// Go online, start acking traffic
|
|
fmt.Printf("\tGoing online... ")
|
|
if res := C.icsneoc2_device_go_online(device, true); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return
|
|
}
|
|
// Redundant check to show how to check if the device is online, if the previous
|
|
// icsneoc2_device_go_online call was successful we can assume we are online already
|
|
var isOnline C.bool = false
|
|
if res := C.icsneoc2_device_is_online(device, &isOnline); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return
|
|
}
|
|
if isOnline {
|
|
println("Online")
|
|
} else {
|
|
println("Offline")
|
|
}
|
|
// Transmit CAN messages
|
|
if !transmitCANMessages(device) {
|
|
return
|
|
}
|
|
// Wait for the bus to collect some messages, requires an active bus to get messages
|
|
println("\tWaiting 1 second for messages...")
|
|
time.Sleep(1 * time.Second)
|
|
// Get the messages
|
|
messages := [20000]*C.icsneoc2_message_t{nil}
|
|
var messagesCount C.uint32_t = 20000
|
|
if res := C.icsneoc2_device_messages_get(device, &messages[0], &messagesCount, 3000); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return
|
|
}
|
|
// Process the messages
|
|
if !processMessages(device, messages[0:messagesCount]) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func printError(err C.icsneoc2_error_t) C.icsneoc2_error_t {
|
|
buffer := make([]byte, 255)
|
|
bufferLength := 255
|
|
res := C.icsneoc2_error_code_get(err, (*C.char)(unsafe.Pointer(&buffer[0])), (*C.uint)(unsafe.Pointer(&bufferLength)))
|
|
if res != C.icsneoc2_error_success {
|
|
println("\ticsneoc2_get_error_code failed, original error:", err)
|
|
return res
|
|
}
|
|
println("\tError:", string(buffer[:bufferLength]))
|
|
return res
|
|
}
|
|
|
|
func printDeviceEvents(device *C.icsneoc2_device_t, deviceDescription string) bool {
|
|
// Get device events
|
|
events := [1024]*C.icsneoc2_event_t{nil}
|
|
var eventsCount C.uint32_t = 1024
|
|
if res := C.icsneoc2_device_events_get(device, &events[0], &eventsCount); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return false
|
|
}
|
|
for i, event := range events[:eventsCount] {
|
|
eventDescription := make([]byte, 255)
|
|
var eventDescriptionLength C.uint32_t = 255
|
|
if res := C.icsneoc2_event_description_get(event, (*C.char)(unsafe.Pointer(&eventDescription[0])), &eventDescriptionLength); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
continue
|
|
}
|
|
fmt.Printf("\t%s: Event %d: %s\n", deviceDescription, i, eventDescription)
|
|
}
|
|
// Get global events
|
|
globalEvents := [1024]*C.icsneoc2_event_t{nil}
|
|
var globalEventsCount C.uint32_t = 1024
|
|
if res := C.icsneoc2_events_get(&globalEvents[0], &globalEventsCount); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return false
|
|
}
|
|
for i, event := range globalEvents[:globalEventsCount] {
|
|
globalEventsDescription := make([]byte, 255)
|
|
var globalEventsDescriptionLength C.uint32_t = 255
|
|
if res := C.icsneoc2_event_description_get(event, (*C.char)(unsafe.Pointer(&globalEventsDescription[0])), &globalEventsDescriptionLength); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
continue
|
|
}
|
|
fmt.Printf("\t%s: Global Event %d: %s\n", deviceDescription, i, globalEventsDescription)
|
|
}
|
|
fmt.Printf("\t%s: Received %d events and %d global events\n", deviceDescription, eventsCount, globalEventsCount)
|
|
|
|
return true
|
|
}
|
|
|
|
func transmitCANMessages(device *C.icsneoc2_device_t) bool {
|
|
var counter uint32 = 0
|
|
const msgCount int = 100
|
|
fmt.Printf("\tTransmitting %d messages...\n", msgCount)
|
|
for range msgCount {
|
|
// Create the message
|
|
var message *C.icsneoc2_message_t = nil
|
|
if res := C.icsneoc2_message_can_create(device, &message, 1); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return false
|
|
}
|
|
defer func() {
|
|
if res := C.icsneoc2_message_can_free(device, message); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
}
|
|
}()
|
|
// Set the message attributes
|
|
res := C.icsneoc2_message_netid_set(device, message, C.icsneoc2_netid_hscan)
|
|
res += C.icsneoc2_message_can_arbid_set(device, message, 0x10)
|
|
res += C.icsneoc2_message_can_canfd_set(device, message, true)
|
|
res += C.icsneoc2_message_can_extended_set(device, message, true)
|
|
res += C.icsneoc2_message_can_baudrate_switch_set(device, message, true)
|
|
// Create the payload
|
|
data := [...]C.uint8_t{
|
|
(C.uint8_t)(counter >> 56),
|
|
(C.uint8_t)(counter >> 48),
|
|
(C.uint8_t)(counter >> 40),
|
|
(C.uint8_t)(counter >> 32),
|
|
(C.uint8_t)(counter >> 24),
|
|
(C.uint8_t)(counter >> 16),
|
|
(C.uint8_t)(counter >> 8),
|
|
(C.uint8_t)(counter >> 0),
|
|
}
|
|
res += C.icsneoc2_message_data_set(device, message, &data[0], (C.uint32_t)(len(data)))
|
|
res += C.icsneoc2_message_can_dlc_set(device, message, -1)
|
|
if res != C.icsneoc2_error_success {
|
|
fmt.Printf("\tFailed to modify message: %d\n", res)
|
|
return false
|
|
}
|
|
var messageCount C.uint32_t = 1
|
|
if res := C.icsneoc2_device_messages_transmit(device, &message, &messageCount); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return false
|
|
}
|
|
counter += 1
|
|
}
|
|
return true
|
|
}
|
|
|
|
func processMessages(device *C.icsneoc2_device_t, messages []*C.icsneoc2_message_t) bool {
|
|
txCount := 0
|
|
for i, message := range messages {
|
|
// Get the message type
|
|
var msgType C.icsneoc2_msg_type_t = 0
|
|
if res := C.icsneoc2_message_type_get(device, message, &msgType); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return false
|
|
}
|
|
// Get the message type name
|
|
msgTypeName := make([]byte, 128)
|
|
var msgTypeNameLength C.uint32_t = 128
|
|
if res := C.icsneoc2_message_type_name_get(msgType, (*C.char)(unsafe.Pointer(&msgTypeName[0])), &msgTypeNameLength); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return false
|
|
}
|
|
// Check if the message is a bus message, ignore otherwise
|
|
if msgType != C.icsneoc2_msg_type_bus {
|
|
fmt.Print("\tIgnoring message type: %d (%s)\n", msgType, msgTypeName)
|
|
continue
|
|
}
|
|
// Get the message bus type
|
|
var msgBusType C.icsneoc2_msg_bus_type_t = 0
|
|
if res := C.icsneoc2_message_bus_type_get(device, message, &msgBusType); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return false
|
|
}
|
|
// Get the bus message type name
|
|
msgBusTypeName := make([]byte, 128)
|
|
var msgBusTypeNameLength C.uint32_t = 128
|
|
if res := C.icsneoc2_bus_type_name_get(msgBusType, (*C.char)(unsafe.Pointer(&msgBusTypeName[0])), &msgBusTypeNameLength); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return false
|
|
}
|
|
// Check if the message is a transmit message
|
|
var isTransmit C.bool = false
|
|
if res := C.icsneoc2_message_is_transmit(device, message, &isTransmit); res != C.icsneoc2_error_success {
|
|
printError(res)
|
|
return false
|
|
}
|
|
if isTransmit {
|
|
txCount += 1
|
|
continue
|
|
}
|
|
fmt.Printf("\t%d) Message type: %d bus type: %s (%d)\n", i, msgType, msgBusTypeName, msgBusType)
|
|
if msgBusType == C.icsneoc2_msg_bus_type_can {
|
|
var arbid C.uint32_t = 0
|
|
var dlc C.int32_t = 0
|
|
var netid C.icsneoc2_netid_t = 0
|
|
var isRemote C.bool = false
|
|
var isCanfd C.bool = false
|
|
var isExtended C.bool = false
|
|
data := make([]byte, 64)
|
|
var dataLength C.uint32_t = 64
|
|
netidName := make([]byte, 128)
|
|
var netidNameLength C.uint32_t = 128
|
|
var res C.icsneoc2_error_t = C.icsneoc2_error_success
|
|
res = C.icsneoc2_message_netid_get(device, message, &netid)
|
|
res += C.icsneoc2_netid_name_get(netid, (*C.char)(unsafe.Pointer(&netidName)), &netidNameLength)
|
|
res += C.icsneoc2_message_can_arbid_get(device, message, &arbid)
|
|
res += C.icsneoc2_message_can_dlc_get(device, message, &dlc)
|
|
res += C.icsneoc2_message_can_is_remote(device, message, &isRemote)
|
|
res += C.icsneoc2_message_can_is_canfd(device, message, &isCanfd)
|
|
res += C.icsneoc2_message_can_is_extended(device, message, &isExtended)
|
|
res += C.icsneoc2_message_data_get(device, message, (*C.uint8_t)(unsafe.Pointer(&data[0])), &dataLength)
|
|
// We really should check the error message for all of these since we can't tell the exact error if something
|
|
// bad happens but for an example this should be okay.
|
|
if res != C.icsneoc2_error_success {
|
|
fmt.Printf("\tFailed to get CAN parameters (error: %d) for index %d\n", res, i)
|
|
continue
|
|
}
|
|
// Finally lets print the RX message
|
|
fmt.Printf("\t NetID: %s (0x%X)\tArbID: 0x%X\t DLC: %d\t Remote: %t\t CANFD: %t\t Extended: %t\t Data length: %d\n", netidName, netid, arbid, dlc, isRemote, isCanfd, isExtended, dataLength)
|
|
fmt.Printf("\t Data: [")
|
|
for _, d := range data[:dataLength] {
|
|
fmt.Printf(" 0x%X", d)
|
|
}
|
|
println(" ]")
|
|
continue
|
|
} else {
|
|
fmt.Printf("\tIgnoring bus message type: %d (%s)\n", msgBusType, msgBusTypeName)
|
|
continue
|
|
}
|
|
|
|
}
|
|
fmt.Printf("\tReceived %d messages total, %d were TX messages\n", len(messages), txCount)
|
|
return true
|
|
}
|