Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // dmx.c
- // Протокол DMX
- //
- #include "dmx.h"
- #include "../drivers.h"
- #include <string.h>
- typedef struct
- {
- TUart Uart;
- TPin Direction;
- } TDMXPort;
- typedef enum
- {
- BREAK,
- MAB,
- DATA
- } TTXState;
- typedef struct
- {
- bool Transmit;
- bool Receive;
- bool Received;
- bool Transmitted;
- bool Active;
- TTXState State;
- void (* onReceive)(uint8_t *, uint16_t);
- void (* onTransmit)(void);
- uint16_t Index;
- uint8_t Buffer[513];
- } TDMXState;
- static const TDMXPort Ports[] = {
- { UART1, { PA, 0 } },
- { UART2, { PA, 1 } },
- { UART3, { PA, 2 } }
- };
- static TDMXState States[sizeof(Ports)/sizeof(Ports[0])];
- static const int PortCount = sizeof(Ports)/sizeof(Ports[0]);
- // Принят Break
- static void dmx_onBreak(uint32_t Port)
- {
- if(States[Port].Receive) States[Port].Received = true;
- States[Port].Index = 0;
- }
- // Принят байт
- static void dmx_onReceive(uint32_t Port, uint8_t Data)
- {
- if(!(States[Port].Receive && States[Port].Active)) return;
- {
- uint16_t Index = States[Port].Index;
- if(Index > 512) return;
- States[Port].Buffer[Index] = Data;
- States[Port].Index = Index + 1;
- }
- }
- // Установить скорость передачи на основе длины одного байта в мкс
- static void dmx_SetBaudrateByWidth(uint32_t Port, uint32_t Microseconds)
- {
- // Вычислим частоту, при которой время передачи каддра (11 бит) будет
- // примерно равна заданной величине
- // При заданной частоте BaudRate 1 бит передаётся за 1000000UL / Baudrate микросекунд.
- // В кадре 11 бит: 1 стартовый + 8 бит данных + 2 стоповых.
- //
- // частота = 11 (бит) * 1000000 (перевод секунд в микросекунды) / количество микросекунд.
- uint32_t BaudRate = 11 * 1000000UL / Microseconds;
- uart_SetBaudrate(Ports[Port].Uart, BaudRate);
- }
- // Отправить BREAK
- static void dmx_SendBreak(uint32_t Port)
- {
- // Отправим BREAK 120 uS (133)
- uart_GPIOMode(Ports[Port].Uart, false);
- dmx_SetBaudrateByWidth(Ports[Port].Uart, 120);
- uart_SendByte(Ports[Port].Uart, 0x00);
- }
- // Отправить MAB
- static void dmx_SendMarkAfterBreak(uint32_t Port)
- {
- // Отправим MAB 20 uS (38)
- uart_GPIOMode(Ports[Port].Uart, true);
- dmx_SetBaudrateByWidth(Ports[Port].Uart, 20);
- uart_SendByte(Ports[Port].Uart, 0x00);
- }
- // Отправить данные, вернт false, если буфер закончился
- static void dmx_SendData(uint32_t Port)
- {
- int32_t Sended = 0;
- const int32_t Size = sizeof(States[Port].Buffer);
- uart_Send(Ports[Port].Uart, &States[Port].Buffer[States[Port].Index], Size - States[Port].Index, &Sended);
- States[Port].Index += Sended;
- }
- // Буфер передачи пуст
- static void dmx_onTransmitted(uint32_t Port)
- {
- switch(States[Port].State)
- {
- case DATA:
- if(States[Port].Index < 513) dmx_SendData(Port);
- break;
- }
- }
- // Передача завершена
- static void dmx_onTransmitCompleted(uint32_t Port)
- {
- switch(States[Port].State)
- {
- case BREAK:
- States[Port].State = MAB;
- dmx_SendMarkAfterBreak(Port);
- break;
- case MAB:
- States[Port].Index = 0;
- States[Port].State = DATA;
- uart_SetBaudrate(Ports[Port].Uart, 250000UL);
- uart_UARTMode(Ports[Port].Uart);
- dmx_SendData(Port);
- break;
- case DATA:
- if(States[Port].Index == 513)
- {
- States[Port].Transmitted = true;
- if(States[Port].Transmit && States[Port].Active)
- {
- dmx_SendBreak(Port);
- States[Port].State = BREAK;
- }
- }
- break;
- }
- if(!States[Port].Transmit) return;
- }
- // Вывод направления - прим
- static void rs485_Receive(uint32_t Port)
- {
- gpio_LowLevel(&Ports[Port].Direction);
- }
- // Вывод направления - передача
- static void rs485_Transmit(uint32_t Port)
- {
- gpio_HighLevel(&Ports[Port].Direction);
- }
- static void dmx_Reset(uint32_t Port)
- {
- memset(&States[Port].Buffer[0], 0, sizeof(States[Port].Buffer));
- States[Port].Active = false;
- States[Port].Receive = false;
- States[Port].Transmit = false;
- }
- // Настройка выбранного порта для работы с DMX
- void dmx_Init(uint32_t Port)
- {
- if(Port >= PortCount) return;
- States[Port].onReceive = 0;
- States[Port].onTransmit = 0;
- dmx_Reset(Port);
- // Управление направлением
- gpio_DigitalOutput(&Ports[Port].Direction);
- rs485_Receive(Port);
- {
- TUart Uart = Ports[Port].Uart;
- uart_Init(Uart, 250000);
- uart_StopBits(Uart, STOP_BITS_2);
- uart_SetPortIndex(Uart, Port);
- uart_SetHandler(Uart, UART_EVENT_ONBREAK, &dmx_onBreak);
- uart_SetHandler(Uart, UART_EVENT_ONRECEIVE, &dmx_onReceive);
- uart_SetHandler(Uart, UART_EVENT_ONTRANSMITTED, &dmx_onTransmitted);
- uart_SetHandler(Uart, UART_EVENT_ONTRANSMITCOMPLETED, &dmx_onTransmitCompleted);
- }
- }
- // Начать приём
- void dmx_Receive(uint32_t Port)
- {
- if(Port >= PortCount) return;
- if(States[Port].Transmit) dmx_Reset(Port);
- States[Port].Receive = true;
- States[Port].Active = true;
- uart_ReceiveEnable(Ports[Port].Uart, true);
- uart_TransmitEnable(Ports[Port].Uart, false);
- rs485_Receive(Port);
- }
- // Начать передачу
- void dmx_Transmit(uint32_t Port)
- {
- if(Port >= PortCount) return;
- if(States[Port].Receive) dmx_Reset(Port);
- States[Port].Transmit = true;
- States[Port].Active = true;
- rs485_Transmit(Port);
- States[Port].State = BREAK;
- dmx_SendBreak(Port);
- uart_ReceiveEnable(Ports[Port].Uart, false);
- uart_TransmitEnable(Ports[Port].Uart, true);
- }
- // Прекратить использование линии
- void dmx_Stop(uint32_t Port)
- {
- if(Port >= PortCount) return;
- uart_ReceiveEnable(Ports[Port].Uart, false);
- uart_TransmitEnable(Ports[Port].Uart, false);
- States[Port].Active = false;
- }
- // Продолжить использование линии
- void dmx_Resume(uint32_t Port)
- {
- if(Port >= PortCount) return;
- States[Port].Active = true;
- if(States[Port].Transmit) dmx_SendBreak(Port);
- uart_ReceiveEnable(Ports[Port].Uart, States[Port].Receive);
- uart_TransmitEnable(Ports[Port].Uart, States[Port].Transmit);
- }
- // Обновить буфер передачи
- void dmx_Update(uint32_t Port, const uint8_t * Data, uint16_t Length)
- {
- if(Port >= PortCount) return;
- memcpy(&States[Port].Buffer[1], Data, sizeof(States[Port].Buffer) - 1);
- }
- // Установить обработчик
- void dmx_SetHandler(uint32_t Port, TDMXEvent Event, void * Handler)
- {
- if(Port >= PortCount) return;
- switch(Event)
- {
- case DMX_EVENT_ONRECEIVE: States[Port].onReceive = (void(*)(uint8_t*,uint16_t))Handler; break;
- case DMX_EVENT_ONTRANSMIT: States[Port].onTransmit = (void(*)(void))Handler; break;
- }
- }
- // Главный цикл
- void dmx_Main(void)
- {
- int i;
- for(i = 0; i < PortCount; i++)
- {
- if(States[i].Transmitted)
- {
- States[i].Transmitted = false;
- if(States[i].onTransmit) States[i].onTransmit();
- }
- if(States[i].Received)
- {
- States[i].Received = false;
- // признак DMX проверим
- if (States[i].Buffer[0] == 0)
- {
- if(States[i].onReceive) States[i].onReceive(&States[i].Buffer[1], sizeof(States[i].Buffer) - 1);
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement