📄 chatmain.c
字号:
// Join request
while ((temp = sendJoinRequest()) != JOIN_ACCEPTED) {
if (temp == JOIN_DENIED) {
printf("\nInvalid nick name / The server is full!");
while (TRUE);
} else {
printf("\nJoin error (RF related)");
halWait(255, CLK_FREQ);
printf(" -> retrying now...");
halWait(255, CLK_FREQ);
}
}
sppSettings.myAddress = pMyCI->address;
// Initialize the ping timeout (we'll reset the countdown each
// time we receive a ping or some other message from the server
noPingTicks = NO_PING_TIMEOUT;
sppSetTimerCB(SPP_CUSTOM_0_TIMER, disconnected, &noPingTicks);
break;
}
}
// Initialize the chat screen
VT100_INIT_CHAT_SCREEN();
// Setup UART0 for interrupt driven I/O
UART0_SETUP(38400, CLK_FREQ, UART_NO_PARITY | UART_RX_TX | UART_ISR);
INT_SETFLAG(INUM_UART0_TX, INT_SET);
// Initialize some chat variables
inPos = 0;
TXI.status = SPP_TX_FINISHED;
txRequest = TX_REQUEST_OFF;
noDecryption = FALSE;
isPrivateMode = FALSE;
printClientList();
// Loop forever
while (TRUE) {
// Turn on reception
RXI.maxDataLen = BUFFER_LENGTH;
RXI.pDataBuffer = pRXBuffer;
sppReceive(&RXI);
// Wait for RF RX to complete
do {
if (txRequest && (TXI.status == SPP_TX_FINISHED) && (RXI.status == SPP_RX_WAITING)) {
sppReset();
}
} while (SPP_STATUS() != SPP_IDLE_MODE);
// Process incoming messages, if any
if (RXI.status == SPP_RX_FINISHED) {
YLED = LED_ON;
processMessage();
YLED = LED_OFF;
}
// Server transmits ping
if (!txRequest && (pMyCI->address == SERVER_ADDRESS)) {
YLED = LED_ON;
// Prepare the transmission settings
TXI.destination = SPP_BROADCAST;
TXI.dataLen = 2;
TXI.pDataBuffer = pAdminTXBuffer;
TXI.flags = MSG_PING;
// Reset the 16-bit array
pAdminTXBuffer[0] = 0x00;
pAdminTXBuffer[1] = 0x00;
// pAdminTXBuffer[0] pAdminTXBuffer[1]
// MSB(15) ... LSB(8) MSB(7) ... LSB(0)
for (n = 1; n < 16; n++) {
if (CI[n].address == INVALID_ADDRESS) {
// Do nothing
} else if (CI[n].address < 8) {
pAdminTXBuffer[1] |= (0x01 << CI[n].address);
} else { // CI[n].address >= 8
pAdminTXBuffer[0] |= (0x01 << (CI[n].address - 8));
}
}
// Send it
sppSend(&TXI);
while (SPP_STATUS() != SPP_IDLE_MODE);
YLED = LED_OFF;
}
// Transmit outgoing messages
if (txRequest) {
YLED = LED_ON;
// PRIVATE MESSAGE
if (isPrivateMode) {
// Make sure that the DES key is valid
pCI = getClientInfo(privateAddress);
if (!pCI->isDESKeyValid) {
// Discard the message if the key exchange fails.
if (!diffieHellmanUp(privateAddress)) {
printStatus(KEY_EXCHANGE_FAILED, privateAddress);
clearInputSection();
isPrivateMode = FALSE;
inPos = 0;
txRequest = TX_REQUEST_OFF;
UART0_FLOW_CONTROL = READY;
} else {
printStatus(KEY_EXCHANGE_OK, privateAddress);
}
}
if (pCI->isDESKeyValid && getClientInfo(privateAddress)) {
// Prepare the transmission settings
TXI.destination = privateAddress;
TXI.flags = (pCI->txFlags & SPP_SEQUENCE_BIT) | SPP_ACK_REQ | SPP_ENCRYPTED_DATA | MSG_CHAT_DOWN;
TXI.dataLen = inPos;
TXI.pDataBuffer = pMessageTXBuffer;
// Encrypt the text with single DES
halDES(DES_SINGLE_DES | DES_ENCRYPT | DES_OFB_MODE, TXI.pDataBuffer, pCI->pDESKey, TXI.dataLen);
// Send it
sppSend(&TXI);
while (SPP_STATUS() != SPP_IDLE_MODE);
// If OK, print the message, clear the input line, and get ready for more input
if (TXI.status == SPP_TX_FINISHED) {
pCI->txFlags = TXI.flags;
sppSettings.rxTimeout = LONG_RX_TIMEOUT;
// We'll have to decrypt the message to be able to print it
halDES(DES_SINGLE_DES | DES_DECRYPT | DES_OFB_MODE, TXI.pDataBuffer, pCI->pDESKey, TXI.dataLen);
printMessage(pMyCI->name, isPrivateMode, pMessageTXBuffer, TXI.dataLen);
clearInputSection();
isPrivateMode = FALSE;
inPos = 0;
txRequest = TX_REQUEST_OFF;
UART0_FLOW_CONTROL = READY;
RLED = LED_OFF;
} else {
sppSettings.rxTimeout = RETRY_TX_TIMEOUT;
RLED = LED_ON;
}
}
// SERVER BROADCAST
} else if (pMyCI->address == SERVER_ADDRESS) {
// Send the message to all clients
broadcastMessage(SERVER_ADDRESS, pMessageTXBuffer, inPos);
// Print the message, clear the input line, and get ready for more input
printMessage(pMyCI->name, isPrivateMode, pMessageTXBuffer, inPos);
clearInputSection();
inPos = 0;
txRequest = TX_REQUEST_OFF;
UART0_FLOW_CONTROL = READY;
// CLIENT BROADCAST (VIA SERVER)
} else {
// Prepare the transmission settings
TXI.destination = SERVER_ADDRESS;
TXI.flags = (getClientInfo(SERVER_ADDRESS)->txFlags & SPP_SEQUENCE_BIT) | SPP_ACK_REQ | MSG_CHAT_UP;
TXI.dataLen = inPos;
TXI.pDataBuffer = pMessageTXBuffer;
// Send the message to the server
sppSend(&TXI);
while (SPP_STATUS() != SPP_IDLE_MODE);
// If OK, print the message, clear the input line, and get ready for more input
if (TXI.status == SPP_TX_FINISHED) {
getClientInfo(SERVER_ADDRESS)->txFlags = TXI.flags;
sppSettings.rxTimeout = LONG_RX_TIMEOUT;
printMessage(pMyCI->name, isPrivateMode, pMessageTXBuffer, inPos);
clearInputSection();
inPos = 0;
txRequest = TX_REQUEST_OFF;
UART0_FLOW_CONTROL = READY;
RLED = LED_OFF;
} else {
sppSettings.rxTimeout = RETRY_TX_TIMEOUT;
RLED = LED_ON;
}
}
YLED = LED_OFF;
}
}
} // main
//----------------------------------------------------------------------------
// UART0 0 interrupt service routine: Message input
//----------------------------------------------------------------------------
void UART0_ISR () interrupt INUM_UART0 {
char typedChar;
// Ignore TX interrupts
if (TI_0) {
INT_SETFLAG(INUM_UART0_TX, INT_CLR);
return;
}
if (RI_0) {
INT_SETFLAG(INUM_UART0_RX, INT_CLR);
// ENTER transmits the message (if there is any)
if ((typedChar = UART0_RECEIVE()) == TERMINAL_KEY_ENTER) {
if (inPos > 0) {
// Send the message
UART0_FLOW_CONTROL = STOP;
txRequest = TX_REQUEST_ON;
}
// Max input length exceeded, or ENTER has already been hit
} else if ((inPos >= MAX_INPUT_LENGTH) || txRequest) {
// Do nothing :)
// BACKSPACE deletes the last character (go back, print space, go back again)
} else if (typedChar == TERMINAL_KEY_BACKSPACE) {
if (inPos > 0) {
INT_SETFLAG(INUM_UART0_TX, INT_SET);
VT100_GO_TO_POS(20, inPos);
putchar(' ');
VT100_GO_TO_POS(20, inPos);
inPos--;
}
// NORMAL (printable) characters
} else if (isprint(typedChar)) {
INT_SETFLAG(INUM_UART0_TX, INT_SET);
// Put the character into the TX buffer
pMessageTXBuffer[inPos++] = typedChar;
// Private mode check (Input begins with "##<")
if (inPos == 3) {
if (pMessageTXBuffer[2] == '<') {
if (isxdigit(pMessageTXBuffer[0]) && isxdigit(pMessageTXBuffer[1])) {
privateAddress = strtoul(pMessageTXBuffer, NULL, 16);
if ((getClientInfo(privateAddress) != NULL) && (privateAddress != pMyCI->address)) {
isPrivateMode = TRUE;
} else {
isPrivateMode = FALSE;
}
} else {
isPrivateMode = FALSE;
}
} else {
isPrivateMode = FALSE;
}
}
// Make it possible to turn off/on the message decryption
if ((inPos == 1) && (pMessageTXBuffer[0] == '<')) {
noDecryption = ~noDecryption;
inPos = 0;
printStatus(DECRYPTION_MODE, NULL);
clearInputSection();
} else {
// Local echo
VT100_GO_TO_POS(20, inPos);
putchar(typedChar);
}
}
// Turn off the UART TX interrupt flag (it will be high because of the putchar() calls)
INT_SETFLAG(INUM_UART0_TX, INT_CLR);
}
} // UART0_ISR
//----------------------------------------------------------------------------
// void disconnected (void)
//
// Description:
// This function is used by clients when the communication with the
// server has broken down.
//----------------------------------------------------------------------------
void disconnected (void) {
printStatus(DISCONNECTED, NULL);
while (TRUE);
} // disconnected
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -