diff --git a/.github/workflows/build-test-python.yml b/.github/workflows/build-test-python.yml index f7500f688..62ed362c2 100644 --- a/.github/workflows/build-test-python.yml +++ b/.github/workflows/build-test-python.yml @@ -27,7 +27,7 @@ jobs: - name: Setup packages on Linux run: | sudo apt-get update - sudo apt-get install libzmq3-dev libsocketcan-dev + sudo apt-get install libzmq3-dev libsocketcan-dev socat - name: Setup build system packages on Linux run: | @@ -59,6 +59,14 @@ jobs: - name: Run ZMQ Python binding Test run: | build/examples/zmqproxy & - PYTHONPATH=builddir python3 examples/python_bindings_example_server.py & - PYTHONPATH=builddir python3 examples/python_bindings_example_client.py -z localhost -s 27 -a 2 + PYTHONPATH=builddir python3 examples/python_bindings_example_server.py -z localhost -a 3 & + PYTHONPATH=builddir python3 examples/python_bindings_example_client.py -z localhost -s 3 -a 2 pkill zmqproxy + + - name: Run KISS Python binding Test + run: | + socat -d -d -d pty,raw,echo=0,link=/tmp/pty1 pty,raw,echo=0,link=/tmp/pty2 & + sleep 1 + PYTHONPATH=builddir python3 examples/python_bindings_example_server.py -k /tmp/pty2 -a 1 & + PYTHONPATH=builddir python3 examples/python_bindings_example_client.py -k /tmp/pty1 -a 2 -s 1 + pkill socat diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 0fa60653e..1ab5cad58 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -24,7 +24,8 @@ jobs: if: ${{ runner.os == 'Linux' }} run: | sudo apt-get update - sudo apt-get install libzmq3-dev libsocketcan-dev socat + sudo apt-get install libzmq3-dev libsocketcan-dev socat iproute2 + sudo apt-get install linux-modules-extra-$(uname -r) - name: Setup build system packages on Linux if: ${{ runner.os == 'Linux' && matrix.buildsystem != 'waf' }} @@ -81,3 +82,24 @@ jobs: ./build/examples/csp_client -z localhost -a 2 -C 1 -T 10 & ./build/examples/csp_server -z localhost -a 1 -t pkill zmqproxy + + - name: Setup vcan0 + run: | + sudo modprobe vcan + sudo ip link add dev vcan0 type vcan + sudo ip link set up vcan0 + echo "Waiting for vcan0 to be up..." + while ! ip -br link show vcan0 | grep -q "UP"; do + sleep 0.1 + done + echo "vcan0 is up" + + - name: Run CAN Server Test + run: | + ./build/examples/csp_server -c vcan0 -a 1 -T 10 & + ./build/examples/csp_client -c vcan0 -a 2 -C 1 -t + + - name: Run CAN Client Test + run: | + ./build/examples/csp_client -c vcan0 -a 2 -C 1 -T 10 & + ./build/examples/csp_server -c vcan0 -a 1 -t diff --git a/contrib/zephyr/samples/server-client/main.c b/contrib/zephyr/samples/server-client/main.c index cda729711..49747bd6c 100644 --- a/contrib/zephyr/samples/server-client/main.c +++ b/contrib/zephyr/samples/server-client/main.c @@ -162,7 +162,7 @@ int main(void) { .stopbits = 1, .paritysetting = 0, }; - int error = csp_usart_open_and_add_kiss_interface(&conf, CSP_IF_KISS_DEFAULT_NAME, &default_iface); + int error = csp_usart_open_and_add_kiss_interface(&conf, CSP_IF_KISS_DEFAULT_NAME, addr, &default_iface); if (error != CSP_ERR_NONE) { LOG_ERR("failed to add KISS interface [%s], error: %d", kiss_device, error); exit(1); diff --git a/examples/csp_client.c b/examples/csp_client.c index 02f7a0d7c..fe2bc39a8 100644 --- a/examples/csp_client.c +++ b/examples/csp_client.c @@ -125,12 +125,11 @@ csp_iface_t * add_interface(enum DeviceType device_type, const char * device_nam .stopbits = 1, .paritysetting = 0, }; - int error = csp_usart_open_and_add_kiss_interface(&conf, CSP_IF_KISS_DEFAULT_NAME, &default_iface); + int error = csp_usart_open_and_add_kiss_interface(&conf, CSP_IF_KISS_DEFAULT_NAME, client_address, &default_iface); if (error != CSP_ERR_NONE) { csp_print("failed to add KISS interface [%s], error: %d\n", device_name, error); exit(1); } - default_iface->addr = client_address; default_iface->is_default = 1; } diff --git a/examples/csp_server.c b/examples/csp_server.c index aaeb8a8e3..eb18095a9 100644 --- a/examples/csp_server.c +++ b/examples/csp_server.c @@ -470,12 +470,11 @@ csp_iface_t * add_interface(enum DeviceType device_type, const char * device_nam .stopbits = 1, .paritysetting = 0, }; - int error = csp_usart_open_and_add_kiss_interface(&conf, CSP_IF_KISS_DEFAULT_NAME, &default_iface); + int error = csp_usart_open_and_add_kiss_interface(&conf, CSP_IF_KISS_DEFAULT_NAME, server_address, &default_iface); if (error != CSP_ERR_NONE) { csp_print("failed to add KISS interface [%s], error: %d\n", device_name, error); exit(1); } - default_iface->addr = server_address; default_iface->is_default = 1; } diff --git a/examples/python_bindings_example_client.py b/examples/python_bindings_example_client.py index ea9de49e0..ef39861be 100644 --- a/examples/python_bindings_example_client.py +++ b/examples/python_bindings_example_client.py @@ -18,10 +18,11 @@ import libcsp_py3 as libcsp -def getOptions(): +def get_options(): parser = argparse.ArgumentParser(description="Parses command.") parser.add_argument("-a", "--address", type=int, default=10, help="Local CSP address") parser.add_argument("-c", "--can", help="Add CAN interface") + parser.add_argument("-k", "--kiss", help="Add KISS interface") parser.add_argument("-z", "--zmq", help="Add ZMQ interface") parser.add_argument("-s", "--server-address", type=int, default=27, help="Server address") parser.add_argument("-R", "--routing-table", help="Routing table") @@ -30,7 +31,7 @@ def getOptions(): if __name__ == "__main__": - options = getOptions() + options = get_options() #initialize libcsp with params: # options.address - CSP address of the system (default=1) @@ -53,7 +54,11 @@ def getOptions(): # Format: \[/mask] \ [via][, next entry] # Examples: "0/0 CAN, 8 KISS, 10 I2C 10", same as "0/0 CAN, 8/5 KISS, 10/5 I2C 10" libcsp.rtable_load("0/0 ZMQHUB") - + + if options.kiss: + libcsp.kiss_init(options.kiss, options.address) + libcsp.rtable_load("0/0 KISS") + if options.routing_table: # same format/use as line above libcsp.rtable_load(options.routing_table) diff --git a/examples/python_bindings_example_server.py b/examples/python_bindings_example_server.py index 84989fbf6..49e89c69f 100644 --- a/examples/python_bindings_example_server.py +++ b/examples/python_bindings_example_server.py @@ -15,8 +15,17 @@ import sys import threading +import argparse + import libcsp_py3 as libcsp +def get_options(): + parser = argparse.ArgumentParser(description="Parses command.") + parser.add_argument("-a", "--address", type=int, default=10, help="Local CSP address") + parser.add_argument("-z", "--zmq", help="Add ZMQ interface") + parser.add_argument("-k", "--kiss", help="Add KISS interface") + return parser.parse_args() + def csp_server(): # parameters: {options} - bit flag corresponding to socket options (see "include\csp\csp_types.h" lines 167-180) @@ -58,21 +67,21 @@ def csp_server(): # extract the data payload from the packet # see "include\csp\csp_types.h" line 215-239 for packet structure data = bytearray(libcsp.packet_get_data(packet)) - + # get length of the data (not the whole packet, just the data length) length = libcsp.packet_get_length(packet) print ("got packet, len=" + str(length) + ", data=" + ''.join('{:02x}'.format(x) for x in data)) - + # send back "input data + 1" data[0] = data[0] + 1 - + # free up a buffer to hold the reply # parameters: {buffer size (# of 4-byte doublewords)} reply = libcsp.buffer_get(0) - + # store the data into the reply buffer libcsp.packet_set_data(reply, data) - + # Send packet as a reply # uses the info (address/port) from the original packet to reply # parameters: @@ -92,6 +101,7 @@ def csp_server(): if __name__ == "__main__": + options = get_options() #initialize libcsp with params: # 27 - CSP address of the system (default=1) # "test_service" - Host name, returned by CSP identity requests @@ -100,18 +110,19 @@ def csp_server(): # See "include\csp\csp.h" - lines 42-80 for more detail # See "src\bindings\python\pycsp.c" - lines 128-156 for more detail libcsp.init("test_service", "bindings", "1.2.3") - - # init zmqhub with parameters: {address (using 255 means all addresses)} {host name/ip} - # subscribe and publish endpoints are created on the default ports using the {host} - # subscribe port = 6000, subscribe port = 7000 - libcsp.zmqhub_init(27, "localhost") - - # params: - # {address} - dest address/node - # {netmask} - number of bits in netmask - # {interface name} - name of interface - # optional{via} - associated with address - libcsp.rtable_set(0, 0, "ZMQHUB") + + if options.zmq: + # add ZMQ interface - (address, host) + # creates publish and subrcribe endpoints from the host + libcsp.zmqhub_init(options.address, options.zmq) + + # Format: \[/mask] \ [via][, next entry] + # Examples: "0/0 CAN, 8 KISS, 10 I2C 10", same as "0/0 CAN, 8/5 KISS, 10/5 I2C 10" + libcsp.rtable_load("0/0 ZMQHUB") + + if options.kiss: + libcsp.kiss_init(options.kiss, options.address) + libcsp.rtable_load("0/0 KISS") # Parameters: {priority} - 0 (critical), 1 (high), 2 (norm), 3 (low) ---- default=2 # Start the router task - creates routing thread diff --git a/include/csp/drivers/usart.h b/include/csp/drivers/usart.h index 41206a9e3..2a68df9f2 100644 --- a/include/csp/drivers/usart.h +++ b/include/csp/drivers/usart.h @@ -95,10 +95,11 @@ void csp_usart_unlock(void * driver_data); * * @param[in] conf UART configuration. * @param[in] ifname internface name (will be copied), or use NULL for default name. + * @param[in] addr CSP address of the interface. * @param[out] return_iface the added interface. * @return #CSP_ERR_NONE on success, otherwise an error code. */ -int csp_usart_open_and_add_kiss_interface(const csp_usart_conf_t * conf, const char * ifname, csp_iface_t ** return_iface); +int csp_usart_open_and_add_kiss_interface(const csp_usart_conf_t * conf, const char * ifname, uint16_t addr, csp_iface_t ** return_iface); #ifdef __cplusplus } diff --git a/src/bindings/python/pycsp.c b/src/bindings/python/pycsp.c index 1f562fd54..4d1525e4b 100644 --- a/src/bindings/python/pycsp.c +++ b/src/bindings/python/pycsp.c @@ -875,13 +875,14 @@ static PyObject * pycsp_kiss_init(PyObject * self, PyObject * args) { char * device; uint32_t baudrate = 500000; uint32_t mtu = 512; + uint16_t addr; const char * if_name = CSP_IF_KISS_DEFAULT_NAME; - if (!PyArg_ParseTuple(args, "s|IIs", &device, &baudrate, &mtu, &if_name)) { + if (!PyArg_ParseTuple(args, "sH|IIs", &device, &addr, &baudrate, &mtu, &if_name)) { return NULL; // TypeError is thrown } csp_usart_conf_t conf = {.device = device, .baudrate = baudrate}; - int res = csp_usart_open_and_add_kiss_interface(&conf, if_name, NULL); + int res = csp_usart_open_and_add_kiss_interface(&conf, if_name, addr, NULL); if (res != CSP_ERR_NONE) { return PyErr_Error("csp_usart_open_and_add_kiss_interface()", res); } diff --git a/src/csp_qfifo.c b/src/csp_qfifo.c index 1fdbbf50e..476d51315 100644 --- a/src/csp_qfifo.c +++ b/src/csp_qfifo.c @@ -8,7 +8,7 @@ static csp_static_queue_t qfifo_queue __noinit; static csp_queue_handle_t qfifo_queue_handle __noinit; -char qfifo_queue_buffer[sizeof(csp_qfifo_t) * CSP_QFIFO_LEN] __noinit; +static char qfifo_queue_buffer[sizeof(csp_qfifo_t) * CSP_QFIFO_LEN] __noinit; void csp_qfifo_init(void) { qfifo_queue_handle = csp_queue_create_static(CSP_QFIFO_LEN, sizeof(csp_qfifo_t), qfifo_queue_buffer, &qfifo_queue); diff --git a/src/csp_rdp.h b/src/csp_rdp.h index ceeaae5ed..87802ce82 100644 --- a/src/csp_rdp.h +++ b/src/csp_rdp.h @@ -10,5 +10,3 @@ int csp_rdp_connect(csp_conn_t * conn); int csp_rdp_close(csp_conn_t * conn, uint8_t closed_by); int csp_rdp_send(csp_conn_t * conn, csp_packet_t * packet); int csp_rdp_check_ack(csp_conn_t * conn); - -void csp_rdp_conn_print(csp_conn_t * conn); diff --git a/src/csp_rdp_queue.c b/src/csp_rdp_queue.c index 72c93ff9f..ceb7576c1 100644 --- a/src/csp_rdp_queue.c +++ b/src/csp_rdp_queue.c @@ -5,7 +5,7 @@ static int __csp_rdp_queue_flush(csp_queue_handle_t queue, csp_conn_t * conn) { - int ret; + int ret = CSP_ERR_NONE; int size; size = csp_queue_size(queue); @@ -85,8 +85,8 @@ void csp_rdp_queue_flush(csp_conn_t * conn) { csp_queue_empty(tx_queue); csp_queue_empty(rx_queue); } else { - (void)__csp_rdp_queue_flush(conn, tx_queue); - (void)__csp_rdp_queue_flush(conn, rx_queue); + (void)__csp_rdp_queue_flush(tx_queue, conn); + (void)__csp_rdp_queue_flush(rx_queue, conn); } } diff --git a/src/csp_yaml.c b/src/csp_yaml.c index 4364bbb08..196af6e4d 100644 --- a/src/csp_yaml.c +++ b/src/csp_yaml.c @@ -70,7 +70,7 @@ static void csp_yaml_end_if(struct data_s * data, unsigned int * dfl_addr) { .stopbits = 1, .paritysetting = 0, }; - int error = csp_usart_open_and_add_kiss_interface(&conf, data->name, &iface); + int error = csp_usart_open_and_add_kiss_interface(&conf, data->name, addr, &iface); if (error != CSP_ERR_NONE) { return; } @@ -206,7 +206,7 @@ void csp_yaml_init(char * filename, unsigned int * dfl_addr) { csp_print(" Reading config from %s\n", filename); FILE * file = fopen(filename, "rb"); if (file == NULL) { - printf(" ERROR: failed to find CSP config file\n"); + csp_print(" ERROR: failed to find CSP config file\n"); return; } diff --git a/src/drivers/CMakeLists.txt b/src/drivers/CMakeLists.txt index e05208860..8d3082971 100644 --- a/src/drivers/CMakeLists.txt +++ b/src/drivers/CMakeLists.txt @@ -15,6 +15,7 @@ endif() if(CMAKE_SYSTEM_NAME STREQUAL "Linux") target_sources(csp PRIVATE usart/usart_linux.c) + target_sources(csp PRIVATE eth/eth_linux.c) elseif(CMAKE_SYSTEM_NAME STREQUAL "Zephyr") target_sources(csp PRIVATE usart/usart_zephyr.c) endif() diff --git a/src/drivers/can/can_socketcan.c b/src/drivers/can/can_socketcan.c index 6e69aee74..81146585d 100644 --- a/src/drivers/can/can_socketcan.c +++ b/src/drivers/can/can_socketcan.c @@ -48,7 +48,7 @@ static void * socketcan_rx_thread(void * arg) { timeout.tv_sec = 10; int n = select(ctx->socket + 1, &input, NULL, NULL, &timeout); if (n == -1) { - printf("CAN read error\n"); + csp_print("CAN read error\n"); continue; } else if (n == 0) { //printf("CAN idle\n"); diff --git a/src/drivers/eth/eth_linux.c b/src/drivers/eth/eth_linux.c index 6f52d6245..590526795 100644 --- a/src/drivers/eth/eth_linux.c +++ b/src/drivers/eth/eth_linux.c @@ -98,7 +98,7 @@ int csp_eth_init(const char * device, const char * ifname, int mtu, unsigned int /* Open RAW socket to send on */ if ((ctx->sockfd = socket(AF_PACKET, SOCK_RAW, htobe16(CSP_ETH_TYPE_CSP))) == -1) { perror("socket"); - printf("Use command 'setcap cap_net_raw+ep ./csh'\n"); + csp_print("Use command 'setcap cap_net_raw+ep ./csh'\n"); return CSP_ERR_INVAL; } diff --git a/src/drivers/usart/usart_kiss.c b/src/drivers/usart/usart_kiss.c index ef0320757..bd9238862 100644 --- a/src/drivers/usart/usart_kiss.c +++ b/src/drivers/usart/usart_kiss.c @@ -30,7 +30,7 @@ static void kiss_driver_rx(void * user_data, uint8_t * data, size_t data_size, v csp_kiss_rx(&ctx->iface, data, data_size, pxTaskWoken); } -int csp_usart_open_and_add_kiss_interface(const csp_usart_conf_t * conf, const char * ifname, csp_iface_t ** return_iface) { +int csp_usart_open_and_add_kiss_interface(const csp_usart_conf_t * conf, const char * ifname, uint16_t addr, csp_iface_t ** return_iface) { if (ifname == NULL) { ifname = CSP_IF_KISS_DEFAULT_NAME; @@ -43,6 +43,7 @@ int csp_usart_open_and_add_kiss_interface(const csp_usart_conf_t * conf, const c strncpy(ctx->name, ifname, sizeof(ctx->name) - 1); ctx->iface.name = ctx->name; + ctx->iface.addr = addr; ctx->iface.driver_data = ctx; ctx->iface.interface_data = &ctx->ifdata; ctx->ifdata.tx_func = kiss_driver_tx; diff --git a/src/interfaces/CMakeLists.txt b/src/interfaces/CMakeLists.txt index 01bcc55bd..50ca4c8d7 100644 --- a/src/interfaces/CMakeLists.txt +++ b/src/interfaces/CMakeLists.txt @@ -5,6 +5,8 @@ target_sources(csp PRIVATE csp_if_tun.c csp_if_can.c csp_if_can_pbuf.c + csp_if_eth.c + csp_if_eth_pbuf.c ) if(LIBZMQ_FOUND) diff --git a/src/interfaces/csp_if_eth_pbuf.c b/src/interfaces/csp_if_eth_pbuf.c index c0b415c3c..cdf54ca5c 100644 --- a/src/interfaces/csp_if_eth_pbuf.c +++ b/src/interfaces/csp_if_eth_pbuf.c @@ -100,7 +100,7 @@ void csp_if_eth_pbuf_list_cleanup(csp_packet_t ** plist) { void csp_if_eth_pbuf_print(const char * descr, csp_packet_t * packet) { if (packet) { - printf("%s %p id:%u Age:%lu,%lu,%lu flen:%u\n", + csp_print("%s %p id:%u Age:%lu,%lu,%lu flen:%u\n", descr, (void *)packet, (unsigned)packet->cfpid, (unsigned long)csp_get_ms(), @@ -108,7 +108,7 @@ void csp_if_eth_pbuf_print(const char * descr, csp_packet_t * packet) { (unsigned long)(csp_get_ms() - packet->last_used), (unsigned)packet->frame_length); } else { - printf("Packet is null\n"); + csp_print("Packet is null\n"); } } diff --git a/src/interfaces/csp_if_kiss.c b/src/interfaces/csp_if_kiss.c index f9be0e0fe..a4cc0c179 100644 --- a/src/interfaces/csp_if_kiss.c +++ b/src/interfaces/csp_if_kiss.c @@ -101,6 +101,7 @@ void csp_kiss_rx(csp_iface_t * iface, const uint8_t * buf, size_t len, void * px /* If no more memory, skip frame */ if (ifdata->rx_packet == NULL) { ifdata->rx_mode = KISS_MODE_SKIP_FRAME; + iface->drop++; break; } diff --git a/src/interfaces/csp_if_zmqhub.c b/src/interfaces/csp_if_zmqhub.c index bc639b4a7..247dde116 100644 --- a/src/interfaces/csp_if_zmqhub.c +++ b/src/interfaces/csp_if_zmqhub.c @@ -210,13 +210,13 @@ int csp_zmqhub_init_w_name_endpoints_rxfilter(const char * ifname, uint16_t addr assert(ret == 0); /* Register interface */ - csp_iflist_add(&drv->iface); + ret = csp_iflist_add(&drv->iface); - if (return_interface) { + if (ret == CSP_ERR_NONE && return_interface) { *return_interface = &drv->iface; } - return CSP_ERR_NONE; + return ret; } int csp_zmqhub_init_filter2(const char * ifname, const char * host, uint16_t addr, uint16_t netmask, int promisc, csp_iface_t ** return_interface, char * sec_key, uint16_t subport, uint16_t pubport) { @@ -312,13 +312,13 @@ int csp_zmqhub_init_filter2(const char * ifname, const char * host, uint16_t add assert(ret == 0); /* Register interface */ - csp_iflist_add(&drv->iface); + ret = csp_iflist_add(&drv->iface); - if (return_interface) { + if (ret == CSP_ERR_NONE && return_interface) { *return_interface = &drv->iface; } - return CSP_ERR_NONE; + return ret; }