diff --git a/examples/projects/product/README.md b/examples/projects/product/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/examples/projects/product/custom_gate/.docker/.dockerignore b/examples/projects/product/custom_gate/.docker/.dockerignore new file mode 100644 index 000000000..55e5d2d0e --- /dev/null +++ b/examples/projects/product/custom_gate/.docker/.dockerignore @@ -0,0 +1,4 @@ +.pio/ +.vscode/ +.gitignore +README.md \ No newline at end of file diff --git a/examples/projects/product/custom_gate/.docker/Dockerfile b/examples/projects/product/custom_gate/.docker/Dockerfile new file mode 100644 index 000000000..a69947544 --- /dev/null +++ b/examples/projects/product/custom_gate/.docker/Dockerfile @@ -0,0 +1,19 @@ +FROM python:3 as builder + +LABEL maintainer="Benjamin Christau " \ + app_name="gate_wscom" + +ENV PLATFORMIO_CORE_DIR="/home" + +WORKDIR /home/app + +COPY . . + +RUN pip install --upgrade pip setuptools wheel platformio && \ + rm -rf /root/.cache/pip + +RUN platformio run \ + --environment native \ + -d ./examples/projects/native/gate_wscom + +CMD [ "./examples/projects/native/gate_wscom/.pio/build/native/program"] diff --git a/examples/projects/product/custom_gate/README.md b/examples/projects/product/custom_gate/README.md new file mode 100644 index 000000000..cd34deef1 --- /dev/null +++ b/examples/projects/product/custom_gate/README.md @@ -0,0 +1,22 @@ +Luos logo + +![](https://github.com/Luos-io/luos_engine/actions/workflows/build.yml/badge.svg) +[![](https://img.shields.io/github/license/Luos-io/luos_engine)](https://github.com/Luos-io/luos_engine/blob/master/LICENSE) + +[![](https://img.shields.io/badge/Luos-Documentation-34A3B4)](https://www.luos.io/docs/) +[![PlatformIO Registry](https://badges.registry.platformio.org/packages/luos/library/luos_engine.svg)](https://registry.platformio.org/libraries/luos_engine/luos_engine) + +[![](https://img.shields.io/discord/902486791658041364?label=Discord&logo=discord&style=social)](http://bit.ly/JoinLuosDiscord) +[![](https://img.shields.io/badge/LinkedIn-Share-0077B5?style=social&logo=linkedin)](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fgithub.com%2Fluos-io) + +# Custom Gate project example :bulb: + +This project demonstrate how to make a custom gate with custom Json conversion. + +## How to compile the code :computer: + +1. Download and install [Platformio](https://platformio.org/platformio-ide) +2. Open this folder into Platformio +3. Build (Platformio will do the rest) + +## Don't hesitate to read [our documentation](https://www.luos.io/docs/), or to post your questions/issues on the [Luos' Discord](http://bit.ly/JoinLuosDiscord). :books: diff --git a/examples/projects/product/custom_gate/node_config.h b/examples/projects/product/custom_gate/node_config.h new file mode 100644 index 000000000..940439740 --- /dev/null +++ b/examples/projects/product/custom_gate/node_config.h @@ -0,0 +1,118 @@ + + +/****************************************************************************** + * @file node_config.h + * @brief This file allow you to use standard preprocessor definitions to + * configure your project, Luos and Luos HAL libraries + * + * # Introduction + * This file is for the luos user. You may here configure your project and + * define your custom Luos service and custom Luos command for your product + * + * Luos libraries offer a minimal standard configuration to optimize + * memory usage. In some case you have to modify standard value to fit + * with your need concerning among of data transiting through the network + * or network speed for example + * + * Luos libraries can be use with a lot a MCU family. Luos compagny give you + * a default configuration, for specific MCU family, in robus_hal_config.h. + * This configuration can be modify here to fit with you design by + * preprocessor definitions of MCU Hardware needs + * + * # Usage + * This file should be place a the root folder of your project and include + * where build flag preprocessor definitions are define in your IDE + * -include node_config.h + * + * @author Luos + * @version 0.0.0 + ******************************************************************************/ +#ifndef _NODE_CONFIG_H_ +#define _NODE_CONFIG_H_ + +/******************************************************************************* + * PROJECT DEFINITION + *******************************************************************************/ + +/******************************************************************************* + * LUOS LIBRARY DEFINITION + ******************************************************************************* + * Define | Default Value | Description + * :---------------------|------------------------------------------------------ + * MAX_LOCAL_SERVICE_NUMBER | 5 | Service number in the node + * MAX_NODE_NUMBER | 20 | Node number in the device + * MAX_SERVICE_NUMBER | 20 | Service number in the device + * MSG_BUFFER_SIZE | 3*SIZE_MSG_MAX (405 Bytes) | Size in byte of the Luos buffer TX and RX + * MAX_MSG_NB | 2*MAX_LOCAL_SERVICE_NUMBER | Message number in Luos buffer + * NBR_PORT | 2 | PTP Branch number Max 8 + * NBR_RETRY | 10 | Send Retry number in case of NACK or collision + ******************************************************************************/ +#define MAX_LOCAL_SERVICE_NUMBER 2 +#define MAX_LOCAL_PROFILE_NUMBER 1 +#define MAX_MSG_NB 200 +#define MSG_BUFFER_SIZE 8192 + +/******************************************************************************* + * LUOS HAL LIBRARY DEFINITION +******************************************************************************* + * Define | Description + * :-----------------------|----------------------------------------------- + * MCUFREQ | Put your the MCU frequency (value in Hz) + * TIMERDIV | Timer divider clock (see your clock configuration) + * USE_CRC_HW | define to 0 if there is no Module CRC in your MCU + * USE_TX_IT | define to 1 to not use DMA transfers for Luos Tx + * + * PORT_CLOCK_ENABLE | Enable clock for port + * PTPx | A,B,C,D etc. PTP Branch Pin/Port/IRQ + * TX_LOCK_DETECT | Disable by default use if not busy flag in USART Pin/Port/IRQ + * RX_EN | Rx enable for driver RS485 always on Pin/Port + * TX_EN | Tx enable for driver RS485 Pin/Port + * COM_TX | Tx USART Com Pin/Port/Alternate + * COM_RX | Rx USART Com Pin/Port/Alternate + * PINOUT_IRQHANDLER | Callback function for Pin IRQ handler + + * ROBUS_COM_CLOCK_ENABLE | Enable clock for USART + * ROBUS_COM | USART number + * ROBUS_COM_IRQ | USART IRQ number + * ROBUS_COM_IRQHANDLER | Callback function for USART IRQ handler + + * ROBUS_DMA_CLOCK_ENABLE | Enable clock for DMA + * ROBUS_DMA | DMA number + * ROBUS_DMA_CHANNEL | DMA channel (depending on MCU DMA may need special config) + + * ROBUS_TIMER_CLOCK_ENABLE | Enable clock for Timer + * ROBUS_TIMER | Timer number + * ROBUS_TIMER_IRQ | Timer IRQ number + * ROBUS_TIMER_IRQHANDLER | Callback function for Timer IRQ handler +******************************************************************************/ + +/******************************************************************************* + * FLASH CONFIGURATION FOR APP WITH BOOTLOADER + ******************************************************************************** + * Define | Default Value | Description + * :---------------------|------------------------------------------------------ + * BOOT_START_ADDRESS | FLASH_BASE = 0x8000000 | Start address of Bootloader in flash + * SHARED_MEMORY_ADDRESS | 0x0800C000 | Start address of shared memory to save boot flag + * APP_START_ADDRESS | 0x0800C800 | Start address of application with bootloader + * APP_END_ADDRESS | FLASH_BANK1_END=0x0801FFFF | End address of application with bootloader + ******************************************************************************/ + +/******************************************************************************* + * GATE SERIAL COM DEFINITION + ******************************************************************************* + * Define | Default Value | Description + * :-------------------------|------------------------------------------------------ + * GATE_BUFF_SIZE | 1024 | Json receive buffer size + * PIPE_RX_BUFFER_SIZE | 1024 | Receive pipe buffer size + * PIPE_TX_BUFFER_SIZE | 2048 | Transmit pipe buffer size + * INIT_TIME | 150 | Wait init time before first detection + ******************************************************************************/ +#define GATE_BUFF_SIZE 65000 +#define PIPE_RX_BUFFER_SIZE 65000 +#define PIPE_TX_BUFFER_SIZE 65000 +#define SERIAL_RX_BUFFER_SIZE 65000 +#define INIT_TIME 150 +#define GATE_REFRESH_TIME_S 0.05f +#define SERIAL_PORT "/dev/cu.usbmodem1202" // "/dev/cu.usbserial-D308N897" + +#endif /* _NODE_CONFIG_H_ */ diff --git a/examples/projects/product/custom_gate/platformio.ini b/examples/projects/product/custom_gate/platformio.ini new file mode 100644 index 000000000..588e39b9d --- /dev/null +++ b/examples/projects/product/custom_gate/platformio.ini @@ -0,0 +1,38 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html +[platformio] +default_envs = native_serial + +[env:native_serial] +lib_ldf_mode =off +lib_extra_dirs = + $PROJECT_DIR/../../../../tool_services/ + $PROJECT_DIR/../../../../../ + $PROJECT_DIR/../../../../network/ +platform = native +lib_deps = + luos_engine@^3.1.0 + serial_network + Pipe + Gate +build_unflags = -Os +build_flags = + -I inc + -I ../ + -include node_config.h + -O1 + -lpthread + -lm + -D LUOSHAL=NATIVE + -D GATEFORMAT=TinyJSON + -D PIPEMODE=WS + -D PIPEHAL=native + -D PIPE_WS_SERVER_ADDR=\"ws://localhost:9342\" ; Watch out you need to escape the " using \ +build_type = debug diff --git a/examples/projects/product/custom_gate/src/custom_json_conversion.c b/examples/projects/product/custom_gate/src/custom_json_conversion.c new file mode 100644 index 000000000..dce3b73a5 --- /dev/null +++ b/examples/projects/product/custom_gate/src/custom_json_conversion.c @@ -0,0 +1,98 @@ +#include "custom-json.h" +#include "product_config.h" +#include + +// This function are called by the gate conversion functions in case of an unknown type. +// This functions allow you to easily add and manage your custom type and commands. + +// This function is called by the gate to convert a service type into a string. +// This is typically used in the end of detection to create a Json representing the device routing table. +// The name of the type will be used by pyluos to create the right object. +const char *Convert_CustomStringFromType(luos_type_t type) +{ + if (type == POINT_2D) + { + return "point_2D"; + } + return NULL; +} + +// This function is called by the gate to convert a piece of Json into a message. +// This is typically used when a Json is received by the gate with an unknown property. +// You can use it to compose your own message out of the Json data and send it to the right service. +void Convert_CustomJsonToMsg(service_t *service, uint16_t target_id, char *property, const json_t *jobj, char *json_str) +{ + msg_t msg; + msg.header.target_mode = IDACK; + msg.header.target = target_id; + // Target linear position 2D + if (property && !strcmp(property, "linear_pos_2D")) + { + // Check the size of the array. If we have more than one data, this mean that this data is a binary size of a trajectory. If we have 2 data, this is an unique point. + json_t const *item = json_getChild(jobj); + if (json_getSibling(item) != NULL) + { + // We only have one point in this data + pos_2d_t pos; + pos.x = (uint16_t)json_getInteger(item); + item = json_getSibling(item); + pos.y = (uint16_t)json_getInteger(item); + // Create the message + msg.header.cmd = LINEAR_POSITION_2D; + msg.header.size = sizeof(pos_2d_t); + memcpy(msg.data, &pos, sizeof(pos_2d_t)); + // Send the message + Luos_SendMsg(service, &msg); + } + else + { + int i = 0; + // This is a binary + int size = (int)json_getInteger(item); + // Find the first \r of the current json_str + for (i = 0; i < GATE_BUFF_SIZE; i++) + { + if (json_str[i] == '\n') + { + i++; + break; + } + } + if (i < GATE_BUFF_SIZE - 1) + { + // Create the message + msg.header.cmd = LINEAR_POSITION_2D; + Luos_SendData(service, &msg, &json_str[i], (unsigned int)size); + } + } + return; + } + if (property && !strcmp(property, "buffer_mode")) + { + msg.data[0] = (char)json_getInteger(jobj); + msg.header.cmd = BUFFER_MODE; + msg.header.size = sizeof(char); + Luos_SendMsg(service, &msg); + return; + } +} + +// This function is called by the gate to convert a message into a piece of Json. +// This is typically used when a message is received by the gate with an unknown command. +// You can use it to compose your own piece of Json out of the message data. +void Convert_CustomMsgToJson(msg_t *msg, char *data) +{ + if (msg->header.cmd == LINEAR_POSITION_2D) + { + // This is our custom message, so we can convert it to JSON + // In this case we will don't need it but I did the code for the sake of the example. + if (msg->header.size == sizeof(pos_2d_t)) + { + // Size ok, now fill the struct from msg data + pos_2d_t pos; + memcpy(&pos, msg->data, msg->header.size); + // create the Json content + sprintf(data, "\"linear_pos_2D\":[%2d,%2d],", pos.x, pos.y); + } + } +} diff --git a/examples/projects/product/custom_gate/src/main.c b/examples/projects/product/custom_gate/src/main.c new file mode 100644 index 000000000..c82b80661 --- /dev/null +++ b/examples/projects/product/custom_gate/src/main.c @@ -0,0 +1,59 @@ +#include "luos_engine.h" +#include "serial_network.h" +#include "pipe.h" +#include "gate.h" +#include + +#ifndef WIN32 + #include + #include + #include + #include + #include +#endif + +void *Gate_Pipe_LoopThread(void *vargp) +{ + while (1) + { + Pipe_Loop(); + Gate_Loop(); + } + return NULL; +} +#ifndef _WIN32 +void handler(int sig) +{ + void *array[10]; + size_t size; + + // get void*'s for all entries on the stack + size = backtrace(array, 10); + + // print out all the frames to stderr + fprintf(stderr, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, STDERR_FILENO); + exit(1); +} +#endif + +int main(void) +{ +#ifndef _WIN32 + signal(SIGSEGV, handler); // install our handler +#endif + Luos_Init(); + Serial_Init(); + Pipe_Init(); + Gate_Init(); + // Create a thread to convert messages into Json and steam them using Websocket + // pthread_t thread_id; + // pthread_create(&thread_id, NULL, Gate_Pipe_LoopThread, NULL); + while (1) + { + Luos_Loop(); + Serial_Loop(); + Pipe_Loop(); + Gate_Loop(); + } +} diff --git a/examples/projects/product/product_config.h b/examples/projects/product/product_config.h new file mode 100644 index 000000000..b2c5d5004 --- /dev/null +++ b/examples/projects/product/product_config.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * @file laser + galvo product_config.h + * @brief A complete product example of a laser + galvo controler with Gate customization. + * @author Luos + * @version 0.0.0 + ******************************************************************************/ +#ifndef PRODUCT_CONFIG_H +#define PRODUCT_CONFIG_H + +#include "luos_engine.h" + +// Definition of a custom service type +typedef enum +{ + POINT_2D = LUOS_LAST_TYPE +} custom_service_type_t; + +// Definition of a custom service command +typedef enum +{ + LINEAR_POSITION_2D = LUOS_LAST_STD_CMD, // uint16_t x, uint16_t y + BUFFER_MODE // 3 different modes: 0: SINGLE, 1: CONTINUOUS, 2: STREAM +} custom_service_cmd_t; + +typedef enum +{ + SINGLE, + CONTINUOUS, + STREAM +} buffer_mode_t; + +typedef struct +{ + uint16_t x; + uint16_t y; +} __attribute__((packed)) pos_2d_t; + +#endif /* PRODUCT_CONFIG_H */