Я запускаю CMUX на 38400, после чего передаю управление на драйвер CMUX:
Код
ATCmdWRPR(5, PHYSICAL_PORT, "AT+CMUX?\r", 500, 2, "OK\r\n", "ERROR\r\n");
ATCmdWRPR(5, PHYSICAL_PORT, "AT+CMUX=0,0,3,127\r", 200, 2, "OK\r\n", "ERROR\r\n");
ATCmdWRPR(5, PHYSICAL_PORT, "AT+CMUX?\r", 500, 2, "OK\r\n", "ERROR\r\n");
vTaskDelay(100);
if ( CMUX_Start() != 0 )
Далее 1 канал использую под управление lwIP стеком, другой - под sms и звонки, третий для постоянной вычитки данных базовых станциях.
Драйвер работает как на WS6318 так и на Quectel M72
Драйвер CMUX, работает вроде, хотя не все в нем реализовано или реализовано корректно, например перевод в энергосберегающий режим у Quectel не только по DTR линии, но надо давать спец. команду, а WS6318 и без команды и без DTR отлично засыпает.
Код плохочитаем, что называется as is:
CODE
#include <stdio.h>
//#include <system.h>
#include "FreeRtos.h"
#include "task.h"
#include "semphr.h"
#include "queue.h"
#include "structs.h"
#include "driver_modem.h"
#include "driver_uart.h"
#include "driver_cmux.h"
#include "ConfigStorage.h"
extern struct T_TrackerSetup TrackerSetup;
extern void MODEM_DMA_New_data_block_decoded( unsigned char * data, unsigned short len, enum E_SERIAL_PORT port);
extern void putchar_modem(unsigned char litera);
void (*CMUX_NewData)(unsigned char * data, unsigned short len, enum E_SERIAL_PORT) = 0;
extern xQueueHandle queue_tcp_strout;
extern xSemaphoreHandle sema_modemtx;
volatile unsigned char packet_rcvd = 0;
unsigned char cmux = 0;
unsigned char N1 = 31;
enum E_CMUX{
CMUX_STATE_WAITSTART = 0,
CMUX_STATE_WAITADRESS,
CMUX_STATE_WAITCONTROL,
CMUX_STATE_WAITLEN1,
CMUX_STATE_WAITLEN2,
CMUX_STATE_WAITDATA,
CMUX_STATE_WAITFCS,
CMUX_STATE_WAITSTOP
};
#define CONTROL_OCTET_SAMB (0x2F)
#define CONTROL_OCTET_UA (0x63)
#define CONTROL_OCTET_DM (0x0F)
#define CONTROL_OCTET_DISC (0x43)
#define CONTROL_OCTET_UIH (0xEF)
#define CONTROL_OCTET_UI (0x03)
volatile enum E_CMUX cmux_state = CMUX_STATE_WAITSTART;
void CMUX_Decode(unsigned char byte)
{
static volatile enum E_SERIAL_PORT port = PHYSICAL_PORT;
static unsigned short data_len = 0;
static unsigned short data_ptr;
static unsigned char buffer[128];
static volatile unsigned char control;
static volatile unsigned char fcs;
if (!cmux)
{
CMUX_NewData(&byte, 1, PHYSICAL_PORT);
return;
}
switch (cmux_state)
{
case CMUX_STATE_WAITSTART:
if (byte == 0xF9)
cmux_state = CMUX_STATE_WAITADRESS;
else
CMUX_NewData(&byte, 1, PHYSICAL_PORT);
break;
case CMUX_STATE_WAITADRESS:
if (byte != 0xF9)
{
cmux_state = CMUX_STATE_WAITCONTROL;
if ( (byte>>2) == 0)
port = VIRTUAL_PORT_0;
else if ( (byte>>2) == 1)
port = VIRTUAL_PORT_1;
else if ( (byte>>2) == 2)
port = VIRTUAL_PORT_2;
else if ( (byte>>2) == 3)
port = VIRTUAL_PORT_3;
else
cmux_state = CMUX_STATE_WAITSTART;
}
break;
case CMUX_STATE_WAITCONTROL:
control = byte;
cmux_state = CMUX_STATE_WAITLEN1;
if (byte == 0xF9)
cmux_state = CMUX_STATE_WAITCONTROL;
break;
case CMUX_STATE_WAITLEN1:
if (byte&0x01)
{
cmux_state = CMUX_STATE_WAITDATA;
data_len = byte>>1;
if (data_len == 0)
cmux_state = CMUX_STATE_WAITFCS;
}
else
{
cmux_state = CMUX_STATE_WAITLEN2;
data_len = byte;
}
data_ptr = 0;
break;
case CMUX_STATE_WAITLEN2:
data_len |= byte<<8;
data_len >>= 1;
cmux_state = CMUX_STATE_WAITDATA;
if (data_len == 0)
cmux_state = CMUX_STATE_WAITFCS;
break;
case CMUX_STATE_WAITDATA:
if (data_len > sizeof(buffer))
{
if (TrackerSetup.error_inform_en)
xQueueSend(queue_tcp_strout, "#M#Error 1\r\n", 0);
cmux_state = CMUX_STATE_WAITSTART;
}
else
{
buffer[data_ptr] = byte;
if (++data_ptr == data_len)
cmux_state = CMUX_STATE_WAITFCS;
}
break;
case CMUX_STATE_WAITFCS:
cmux_state = CMUX_STATE_WAITSTOP;
fcs = byte;
break;
case CMUX_STATE_WAITSTOP:
if (byte == 0xF9)
{
//&& ((control&0xEF) != CONTROL_OCTET_UA)&& ((control&0xEF) != CONTROL_OCTET_UA) )
if ( data_len )
CMUX_NewData(buffer, data_len, port);
else
packet_rcvd = 1;
}
else
{
CMUX_NewData(&byte, 1, PHYSICAL_PORT);
if (TrackerSetup.error_inform_en)
xQueueSend(queue_tcp_strout, "#M#Error 2\r\n", 0);
}
cmux_state = CMUX_STATE_WAITSTART;
break;
default:
break;
}
}
void CMUX_AssignCallback(void (* callback)(unsigned char *, unsigned short, enum E_SERIAL_PORT))
{
CMUX_NewData = callback;
}
unsigned char CMUX_Init(unsigned char n1)
{
N1 = n1;
CMUX_AssignCallback( MODEM_DMA_New_data_block_decoded );
return 0;
}
const char cmux_a_open_dlci0[] = {0x03, 0x3F, 0x01};
const char cmux_a_close_dlci0[] = {0x03, 0xEF, 0x05, 0xC3, 0x01};
const char cmux_a_open_dlci[][3] ={
{0x07, 0x3F, 0x01},
{0x0B, 0x3F, 0x01},
{0x0F, 0x3F, 0x01}
};
const char cmux_a_setup_msc[][5] = {
{0xE3, 0x07, 0x07, 0x0D, 0x01},
{0xE3, 0x07, 0x0B, 0x0D, 0x01},
{0xE3, 0x07, 0x0F, 0x0D, 0x01}
};
const char cmux_a_close_dlci [][3] = {
{0x07, 0x53, 0x01},
{0x0B, 0x53, 0x01},
{0x0F, 0x53, 0x01}
};
unsigned char CMUX_IsPacketRcvd(void)
{
vTaskDelay(50);
if (packet_rcvd == 1)
{
packet_rcvd = 0;
return 1;
}
else
{
return 0;
}
}
unsigned char CMUX_Start(void)
{
cmux = 1;
if (CMUX_OpenChannel(0))
{
cmux = 0;
return 1;
}
if (CMUX_OpenChannel(1))
return 2;
if (CMUX_OpenChannel(2))
return 3;
if (CMUX_OpenChannel(3))
return 4;
return 0;
}
unsigned char CMUX_Stop(void)
{
if (CMUX_CloseChannel(3))
return 4;
if (CMUX_CloseChannel(2))
return 3;
if (CMUX_CloseChannel(1))
return 2;
if (CMUX_CloseChannel(0))
return 1;
cmux = 0;
return 0;
}
void CMUX_SendControl(char * str, unsigned char len)
{
unsigned char fsc = CalcFCS((unsigned char *)str, len);
putchar_modem( 0xF9);
for (unsigned char i = 0; i < len; i++)
putchar_modem( str[i] );
putchar_modem( fsc);
putchar_modem( 0xF9);
}
unsigned char CMUX_CloseChannel(unsigned char channel)
{
unsigned char counter;
switch(channel)
{
case 0:
counter = 10;
do
CMUX_SendControl( (char *)cmux_a_close_dlci0, sizeof(cmux_a_close_dlci0));
while (!CMUX_IsPacketRcvd() && counter--);
if ( !counter )
{
xSemaphoreGive( sema_modemtx );
return 1;
}
break;
case 1:
case 2:
case 3:
counter = 10;
do
CMUX_SendControl((char *)cmux_a_close_dlci[channel - 1], sizeof(cmux_a_close_dlci[channel - 1]));
while (!CMUX_IsPacketRcvd() && counter--);
if ( !counter )
{
xSemaphoreGive( sema_modemtx );
return channel + 1;
}
break;
}
xSemaphoreGive( sema_modemtx );
return 0;
}
unsigned char CMUX_OpenChannel(unsigned char channel)
{
unsigned char counter;
switch(channel)
{
case 0:
counter = 10;
do
CMUX_SendControl((char *)cmux_a_open_dlci0, sizeof(cmux_a_open_dlci0));
while (!CMUX_IsPacketRcvd() && counter--);
if ( !counter ) return 1;
break;
case 1:
case 2:
case 3:
counter = 10;
do
CMUX_SendControl((char *)cmux_a_open_dlci[channel-1], sizeof(cmux_a_open_dlci[channel-1]));
while (!CMUX_IsPacketRcvd() && counter--);
if ( !counter ) return 1;
counter = 10;
do
CMUX_SendData((char *)cmux_a_setup_msc[channel - 1], sizeof(cmux_a_setup_msc[channel - 1]), VIRTUAL_PORT_0);
while (!CMUX_IsPacketRcvd() && counter--);
if ( !counter ) return 1;
break;
}
return 0;
}
void CMUX_Reset(void)
{
xSemaphoreGive( sema_modemtx );
cmux = 0;
}
unsigned char CMUX_GetStatus(void)
{
return cmux;
}
static const unsigned char crctable[256] = { //reversed, 8-bit, poly=0x07
0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
};
unsigned char CalcFCS( unsigned char *buf, int len)
{
unsigned char FCS=0xFF;
while (len--) FCS=crctable[FCS^*buf++];
return (0xFF-FCS);
}
int CheckFCS( unsigned char *buf, int len)
{
unsigned char FCS=0xFF ;
while (len--)
{
FCS=crctable[FCS^*buf++];
}
// 0xCF is the reversed order of 11110011.
return (FCS==0xCF);
}
void CMUX_SetN1(unsigned char n1)
{
N1 = n1;
}
void CMUX_SendData(char * data, unsigned short len, enum E_SERIAL_PORT virtual_port)
{
xSemaphoreTake( sema_modemtx, portMAX_DELAY );
switch (virtual_port)
{
case PHYSICAL_PORT:
while (len--)
putchar_modem( *data++);
break;
case VIRTUAL_PORT_0:
case VIRTUAL_PORT_1:
case VIRTUAL_PORT_2:
case VIRTUAL_PORT_3:
while (len)
{
unsigned char local_counter = N1;
unsigned char fcalc[3];
putchar_modem( 0xF9);
if (virtual_port == VIRTUAL_PORT_0)
fcalc[0] = 0x01;
if (virtual_port == VIRTUAL_PORT_1)
fcalc[0] = 0x05;
else if (virtual_port == VIRTUAL_PORT_2)
fcalc[0] = 0x09;
else //if (virtual_port == VIRTUAL_PORT_3)
fcalc[0] = 0x0D;
putchar_modem( fcalc[0]);
fcalc[1] = 0xEF;
putchar_modem( fcalc[1]);
// len
if (len>N1)
fcalc[2] = (N1<<1)|0x01;
else
fcalc[2] = (len<<1)|0x01;
putchar_modem( fcalc[2]);
while (local_counter-- && len)
{
putchar_modem( *data++);
len--;
}
putchar_modem( CalcFCS(fcalc, 3));
putchar_modem( 0xF9);
}
break;
}
xSemaphoreGive( sema_modemtx );
}
Надеюсь поможет:-)