PPPOS कार्यान्वयन stm32f4- खोज पर

एक बार, मुझसे पहले STM32 पर इंटरनेट का उपयोग प्रदान करने के लिए एक कार्य था, जिसमें केवल COM पोर्ट था। इस समस्या को हल करने के लिए, मुझे पीपीपी की आवश्यकता थी, या, सटीक होने के लिए, पीपीपीओएस (सीरियल पर प्वाइंट-टू-पॉइंट प्रोटोकॉल - पीपीपी को लागू करने के तरीकों में से एक, इसे COM पोर्ट के माध्यम से कनेक्ट करते समय उपयोग किया जाता है)।

मेरे सामने निर्धारित कार्य को हल करने की प्रक्रिया में, मुझे कुछ कठिनाइयों का सामना करना पड़ा, जिनमें से एक, मेरी राय में, इंटरनेट पर पीपीपीओएस से संबंधित मुद्दों का अपर्याप्त कवरेज था। इस पोस्ट के साथ मैं निर्दिष्ट अंतर को बंद करने की कोशिश करूंगा, जहां तक ​​मेरा मामूली ज्ञान अनुमति देगा।

यह आलेख वर्णन करता है कि खरोंच से STM32 के लिए सिस्टम कार्यक्षेत्र के लिए एक प्रोजेक्ट कैसे बनाया जाए। UART के साथ काम करने का एक उदाहरण दिखाता है। पीपीपी को लागू करने के लिए कोड उदाहरण हैं। और निश्चित रूप से, पड़ोसी कंप्यूटर पर एक संदेश भेजने का एक उदाहरण।

परिचय


PPP (पॉइंट-टू-पॉइंट प्रोटोकॉल) OSI नेटवर्क मॉडल का दो-बिंदु डेटा लिंक प्रोटोकॉल है। यह आमतौर पर दो नेटवर्क नोड्स के बीच सीधा संचार स्थापित करने के लिए उपयोग किया जाता है, और यह कनेक्शन प्रमाणीकरण, एन्क्रिप्शन और डेटा संपीड़न प्रदान कर सकता है। कई प्रकार के भौतिक नेटवर्क पर उपयोग किया जाता है: नल मॉडेम केबल, टेलीफोन लाइन, सेलुलर, आदि।

अक्सर पीपीपी प्रोटोकॉल की उप-प्रजातियां होती हैं, जैसे कि ईथरनेट (PPPoE) पर पॉइंट-टू-पॉइंट प्रोटोकॉल, ईथरनेट के माध्यम से कनेक्ट करने के लिए, और कभी-कभी डीएसएल के माध्यम से; और ATM से अधिक पॉइंट प्रोटोकॉल (PPPoA), जिसका उपयोग ATM Adaptation Layer 5 (AAL5) के माध्यम से कनेक्शन के लिए किया जाता है, जो कि DSL के लिए मुख्य PPPoE विकल्प है।

PPP प्रोटोकॉल का एक परिवार है: लिंक कंट्रोल प्रोटोकॉल (LCP), नेटवर्क कंट्रोल प्रोटोकॉल (NCP), ऑथेंटिकेशन प्रोटोकॉल (PAP, CHAP), मल्टीचैनल PPP (MLPPP)।

विकिपीडिया से

ट्रेनिंग


समस्या के समाधान के लिए हमें चाहिए:

लोहा:


  1. डिबग बोर्ड stm32f4_discovery:

  2. कंप्यूटर से बोर्ड को जोड़ने के लिए यूएसबी मिनीयूएसबी एडाप्टर के लिए।
  3. दो USBtoUART FT232 एडेप्टर:

  4. दो यूएसबी एक्सटेंशन केबल भी उपयोगी हैं, जरूरी नहीं, लेकिन सिर्फ सुविधाजनक।

शीतल:


  1. वर्चुअल मशीन VirtualBox। आप इसे यहाँ डाउनलोड कर सकते हैं । हम VirtualBox के लिए एक्सटेंशन पैक को भी डाउनलोड और इंस्टॉल करते हैं।
  2. ऑपरेटिंग सिस्टम विंडोज और लिनक्स के साथ दो इंस्टॉलेशन डिस्क। विंडोज ले यहाँ लिनक्स, यहाँ

    ओएस स्थापित करने के बाद, आपको अतिथि ओएस के लिए ऐड-ऑन स्थापित करना होगा। कार्य के लिए हमारे पास पर्याप्त 32x सिस्टम हैं, आप वर्चुअलाइजेशन के समावेश के साथ मूर्ख नहीं बना सकते हैं।
  3. विंडोज के लिए, हमें एक कार्यक्रम की आवश्यकता है जो टीसीपी / आईपी के माध्यम से अनुरोध स्वीकार कर सकता है और उन्हें जवाब दे सकता है, और एक COM पोर्ट के साथ काम करने के लिए एक टर्मिनल प्रोग्राम। यहां पैकटसेन्डर डाउनलोड करें ("नहीं धन्यवाद, बस मुझे डाउनलोड करने पर क्लिक करें"), टर्मिनल यहां है । इसके अलावा, हमें प्रोजेक्ट के शुरुआती सेटअप के लिए STM32CubeMX की आवश्यकता है। St.com से डाउनलोड करें (पंजीकरण के बाद, लिंक ई-मेल से आएगा)।
  4. हमने मुख्य OS पर STM32 के लिए सिस्टम कार्यक्षेत्र को रखा। यहां से डाउनलोड करें (पंजीकरण आवश्यक)।

चरण 1. एक परियोजना बनाना


सबसे पहले, STM32CubeMX खोलें और हमारे stm32f4- डिस्कवरी बोर्ड के लिए एक नया प्रोजेक्ट बनाएं। RCC, ईथरनेट (ETH), SYS, USART2, USART3, फिर FREERTOS और LWIP चालू करें।




डायग्नोस्टिक्स के लिए, हमें बोर्ड पर एलईडी की आवश्यकता होती है। इसके लिए, PD12-PD15 के पैरों को GPIO_Output के रूप में कॉन्फ़िगर करें।



क्लॉक कॉन्फ़िगरेशन टैब पर, आवृत्ति सेट करें, जैसा कि नीचे दी गई तस्वीर में है।



अगला, कॉन्फ़िगरेशन टैब पर, USART पोर्ट कॉन्फ़िगर करें। हम उनके साथ डीएमए मोड में काम करेंगे। हमारे पास दो USART पोर्ट हैं, एक हम पीपीपी के माध्यम से डेटा संचारित और प्राप्त करने के लिए उपयोग करेंगे, दूसरा लॉगिंग के लिए। उन्हें काम करने के लिए, हमें दोनों बंदरगाहों के लिए RX और TX पर DMA को कॉन्फ़िगर करने की आवश्यकता है। सभी डीएमए ट्यूनिंग पैरों के लिए, मध्यम को प्राथमिकता पर सेट करें। USART2 लेग आरएक्स के लिए "सर्कुलर" मोड सेट करें। बाकी सेटिंग्स डिफ़ॉल्ट रूप से छोड़ दी जाती हैं।



आपको "NVIC सेटिंग्स" टैब पर दोनों बंदरगाहों के लिए वैश्विक रुकावट को सक्षम करने की आवश्यकता होगी।

यह STM32CubeMX में प्रोजेक्ट के प्रारंभिक सेटअप को पूरा करता है। हम प्रोजेक्ट फ़ाइल सहेजते हैं और STM32 के लिए सिस्टम कार्यक्षेत्र के लिए कोड जनरेशन करते हैं।



कार्यान्वयन


अब यह सत्यापित करते हैं कि डाउनलोड किया गया कोड संकलन और काम करता है। ऐसा करने के लिए, "StartDefaultTask" फ़ंक्शन में main.c फ़ाइल में, हम एलईडी (और;) कोड के लिए लूप के साथ अनंत के शरीर को प्रतिस्थापित करते हैं।

यह इस तरह होना चाहिए:

/* StartDefaultTask function */ void StartDefaultTask(void const * argument) { /* init code for LWIP */ MX_LWIP_Init(); /* USER CODE BEGIN 5 */ /* Infinite loop */ for(;;) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET); osDelay(1000); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET); osDelay(1000); } /* USER CODE END 5 */ } 

हम फर्मवेयर को संकलित करते हैं और देखो। सभी चार एलईडी को बोर्ड पर झपका देना चाहिए।

चरण 2. USART के साथ काम करें


हमारा अगला काम हमारी USART के सही संचालन को सत्यापित करना है।

पहली चीज़ जो हमें करने की ज़रूरत है वह हमारे FT232 को डिस्कवरी से कनेक्ट करना है। ऐसा करने के लिए, देखें कि USART इंटरफेस किन पैरों से तलाकशुदा हैं। मेरे पास क्रमशः USART2_RX और USART2_TX के लिए PD6 और PD5 है।



USART3_RX और USART3_TX के लिए PD9 और PD8 क्रमशः।



इसके अलावा, हमें एक GND फुट की आवश्यकता है।

हम बोर्ड पर इन पिनों को ढूंढते हैं और उन्हें FT232 पिनों से जोड़ते हैं, जबकि बोर्ड पर GND पिन कोई भी हो सकता है, बोर्ड पर RX पिन FT232 पर TX पिन से जुड़ा होना चाहिए, और बोर्ड पर TX पिन FT232 पर RX पिन से जुड़ा होना चाहिए। शेष निष्कर्षों का उपयोग नहीं किया जाता है।

यह हमारे FT232 को कंप्यूटर के यूएसबी पोर्ट से कनेक्ट करने के लिए रहता है, साथ ही डिस्कवरी बोर्ड को मिनीयूएसबी कनेक्टर के माध्यम से कंप्यूटर से कनेक्ट करता है (माइक्रोयूएसबी से भ्रमित नहीं होने के लिए)।

FT232 को जोड़ने के बाद, मुख्य ओएस उनके लिए ड्राइवरों को स्थापित करेगा, जिसके बाद इन उपकरणों को वर्चुअल मशीन पर विंडोज अतिथि को अग्रेषित करना होगा।

अब हम उस प्रोग्राम कोड को जोड़ते हैं जो हमारे USART के संचालन के लिए आवश्यक है। ऐसा करने के लिए, हम चार फाइलें जोड़ेंगे: usart.h, usart.c, logger.h, logger.c।

फ़ाइल सामग्री:

usart.h फ़ाइल
 #ifndef _USART_ #define _USART_ #include "stm32f4xx_hal.h" void usart_Open(void); bool usart_Send(char* bArray, int size_bArray); uint16_t usart_Recv(char* bArray, uint16_t maxLength); #endif /* _USART_ */ 

usart.c फ़ाइल
 #include "usart.h" #include "logger.h" #include "cmsis_os.h" #define Q_USART2_SIZE 200 xQueueHandle g_qUsart; osThreadId g_usart_rxTaskHandle; extern UART_HandleTypeDef huart2; void usart_rxTask(void); uint8_t bGet[Q_USART2_SIZE] = {0}; uint16_t g_tail = 0; void usart_Open(void) { g_qUsart = xQueueCreate( Q_USART2_SIZE, sizeof( unsigned char ) ); osThreadDef(usart_rxTask_NAME, usart_rxTask, osPriorityNormal, 0, Q_USART2_SIZE/4+128); g_usart_rxTaskHandle = osThreadCreate(osThread(usart_rxTask_NAME), NULL); HAL_UART_Receive_DMA(&huart2, bGet, Q_USART2_SIZE); } void usart_rxTask(void) { for(;;) { uint16_t length = Q_USART2_SIZE - huart2.hdmarx->Instance->NDTR; while(length - g_tail) { uint8_t tmp = bGet[g_tail]; xQueueSendToBack( g_qUsart, &tmp, 100 ); g_tail++; if (g_tail == Q_USART2_SIZE) g_tail = 0; } } } bool usart_Send(char* bArray, int size_bArray) { HAL_StatusTypeDef status; status = HAL_UART_Transmit_DMA(&huart2, bArray, size_bArray); while (HAL_UART_GetState(&huart2) != HAL_UART_STATE_READY) { if (HAL_UART_GetState(&huart2) == HAL_UART_STATE_BUSY_RX) break; osDelay(1); } if (status == HAL_OK) return true; return false; } uint16_t usart_Recv(char* bArray, uint16_t maxLength) { uint8_t tmp = 0; uint16_t length = 0; while(uxQueueMessagesWaiting(g_qUsart)) { xQueueReceive( g_qUsart, &tmp, 100 ); bArray[length] = tmp; length++; if (length >= maxLength) break; } return length; } 

logger.h फ़ाइल
 #ifndef _LOGGER_ #define _LOGGER_ void logger(const char *format, ...); #endif /* _LOGGER_ */ 

logger.c फ़ाइल
 #include "logger.h" #include "stm32f4xx_hal.h" #include <stdarg.h> extern UART_HandleTypeDef huart3; #define MAX_STRING_SIZE 1024 HAL_StatusTypeDef logger_Send(char* bArray, uint32_t size_bArray) { HAL_StatusTypeDef status; for(int i=0;i<5;i++) { status = HAL_UART_Transmit_DMA(&huart3, bArray, size_bArray); if (status == HAL_OK) break; osDelay(2); } while (HAL_UART_GetState(&huart3) != HAL_UART_STATE_READY) { osDelay(1); } return status; } void logger(const char *format, ...) { char buffer[MAX_STRING_SIZE]; va_list args; va_start (args, format); vsprintf(buffer, format, args); va_end(args); buffer[MAX_STRING_SIZE-1]=0; logger_Send(buffer, strlen(buffer)); } 

हमें usart2 पर डेटा संचारित और प्राप्त करने के लिए usart की आवश्यकता है। पीपीपी सर्वर के साथ संचार करने के लिए यह हमारा मुख्य इंटरफेस होगा।

हमें टर्मिनल पर संदेश भेजकर लॉगिंग को लागू करने के लिए लकड़हारा चाहिए। शून्य usart_Open (शून्य) फ़ंक्शन एक कतार बनाता है और इस कतार को सेवित करने का कार्य शुरू करता है। USART का उपयोग करने से पहले इस फ़ंक्शन को पूरा किया जाना चाहिए। फिर सब कुछ सरल है, बूल usart_Send फ़ंक्शन (चार * bArray, int size_bArray) पोर्ट पर डेटा भेजता है, और
uint16_t usart_Recv (char * bArray, uint16_t maxLength) उन्हें उस कतार से प्राप्त करता है जिसमें शून्य usart_rxTask (शून्य) फ़ंक्शन ने कृपया उन्हें जोड़ा है।

लकड़हारा के लिए, यह अभी भी सरल है, डेटा प्राप्त करने की कोई आवश्यकता नहीं है, इसलिए, न तो कतार और न ही कतार रखरखाव कार्य की आवश्यकता है।

Main.h फ़ाइल की शुरुआत में, आपको बूल प्रकार का वर्णन करते हुए कई परिभाषित जोड़ने की आवश्यकता होती है, जो C में उपलब्ध नहीं है।

 /* USER CODE BEGIN Includes */ typedef unsigned char bool; #define true 1 #define false 0 /* USER CODE END Includes */ 

अब परिणामस्वरूप कोड की कार्यक्षमता की जांच करने का समय है। ऐसा करने के लिए, main.c फ़ाइल में, पहले से ज्ञात कार्य "StartDefaultTask" का कोड बदल दें।

 /* USER CODE BEGIN 4 */ #include "usart.h" #include "logger.h" #define MAX_MESSAGE_LENGTH 100 /* USER CODE END 4 */ /* StartDefaultTask function */ void StartDefaultTask(void const * argument) { /* init code for LWIP */ MX_LWIP_Init(); /* USER CODE BEGIN 5 */ usart_Open(); /* Infinite loop */ uint8_t send[] = "Send message\r\n"; uint8_t recv[MAX_MESSAGE_LENGTH] = {0}; uint16_t recvLength = 0; for(;;) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET); osDelay(1000); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET); osDelay(1000); if (usart_Send(send, sizeof(send)-1)) logger("SEND - %s", send); recvLength = usart_Recv(recv, MAX_MESSAGE_LENGTH-1); if (recvLength) { recv[recvLength] = 0; logger("RECV - %s\r\n", recv); } } /* USER CODE END 5 */ } 

इसके अलावा, हमें अपने कार्य के ढेर को अधिक स्मृति देने की आवश्यकता है। ऐसा करने के लिए, osThreadDef () फ़ंक्शन, main.c फ़ाइल में कॉल करने के लिए, आपको इसे प्राप्त करने के लिए 128 * 10 * से 128 ठीक करने की आवश्यकता है:

 osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, <b>128*10</b>); 

हम संकलन और फ्लैश करते हैं। एलइडी पलक झपकते ही पिछले कार्य की तरह हो जाती है।

हमारे काम के परिणाम को देखने के लिए, आपको हमारी वर्चुअल मशीन में टर्मिनल प्रोग्राम चलाने की आवश्यकता है। लॉगिंग पोर्ट के लिए कार्यक्रम का एक उदाहरण, मुख्य के लिए दूसरा। डिवाइस मैनेजर में देखें कि आपके FT232 को कौन से पोर्ट नंबर सौंपे गए हैं। यदि संख्या को 10 से अधिक सौंपा गया है, तो पुन: असाइन करें।

जब आप प्रोग्राम का दूसरा उदाहरण शुरू करते हैं, तो एक त्रुटि हो सकती है, त्रुटि के साथ विंडो बंद करें और प्रोग्राम के साथ काम करना जारी रखें।

दोनों बंदरगाहों के लिए हम 115200 बॉड, डेटा बिट्स - 8, समता - कोई नहीं, बिट्स स्टॉप - 1, हैंडशेकिंग - कोई भी स्थापित नहीं करते।

यदि आपने सब कुछ सही ढंग से किया है, तो usart2 के लिए टर्मिनल विंडो में "संदेश भेजें" संदेश प्रेषित किया जाएगा। उसी संदेश को उपसर्ग "SEND -" के साथ केवल लकड़हारा के लिए टर्मिनल विंडो में डुप्लिकेट किया जाएगा

यदि usart2 के लिए टर्मिनल विंडो में आप "भेजें" फ़ील्ड में कुछ पाठ लिखते हैं और इस फ़ील्ड के दाईं ओर संबंधित बटन पर क्लिक करते हैं, तो लकड़हारा विंडो में आपको उपसर्ग "RECV -" के साथ एक ही संदेश दिखाई देगा

नीचे दी गई तस्वीर में: बाईं ओर लकड़हारा है, दाईं ओर usart2 है।



स्टेज 3. पीपीपी के साथ शुरुआत करना


इस कार्य के हिस्से के रूप में, हम पीपीपी कनेक्शन जुटाएंगे। सबसे पहले, पीपीपी के उपयोग को सक्षम करें, पीपीपी_सुपोर्ट के मान को ppp_opts.h फ़ाइल में 1 में बदलें। फिर हम lwipopts.h फ़ाइल में आवश्यक परिभाषित को फिर से परिभाषित करें,

 /* USER CODE BEGIN 1 */ #define MEMP_NUM_SYS_TIMEOUT 8 #define CHECKSUM_GEN_IP 1 #define CHECKSUM_GEN_TCP 1 /* USER CODE END 1 */ 

इसी समय, पुराने परिभाषित करने के लिए टिप्पणी करने की आवश्यकता है।

अब हम lwip.c फ़ाइल को संशोधित करते हैं, निम्नलिखित कोड को "/ * USER CODE BEGIN 0 * /" ब्लॉक में डालें:

 /* USER CODE BEGIN 0 */ #include "usart.h" #include "pppos.h" #include "sio.h" #include "dns.h" #include "ppp.h" static ppp_pcb *ppp; struct netif pppos_netif; void PppGetTask(void const * argument) { uint8_t recv[2048]; uint16_t length = 0; for(;;) { length=usart_Recv(recv, 2048); if (length) { pppos_input(ppp, recv, length); logger("read - PppGetTask() len = %d\n", length); } osDelay(10); } } #include "ip4_addr.h" #include "dns.h" static void ppp_link_status_cb(ppp_pcb *pcb, int err_code, void *ctx) { struct netif *pppif = ppp_netif(pcb); LWIP_UNUSED_ARG(ctx); switch(err_code) { case PPPERR_NONE: /* No error. */ { logger("ppp_link_status_cb: PPPERR_NONE\n\r"); logger(" our_ip4addr = %s\n\r", ip4addr_ntoa(netif_ip4_addr(pppif))); logger(" his_ipaddr = %s\n\r", ip4addr_ntoa(netif_ip4_gw(pppif))); logger(" netmask = %s\n\r", ip4addr_ntoa(netif_ip4_netmask(pppif))); } break; case PPPERR_PARAM: /* Invalid parameter. */ logger("ppp_link_status_cb: PPPERR_PARAM\n"); break; case PPPERR_OPEN: /* Unable to open PPP session. */ logger("ppp_link_status_cb: PPPERR_OPEN\n"); break; case PPPERR_DEVICE: /* Invalid I/O device for PPP. */ logger("ppp_link_status_cb: PPPERR_DEVICE\n"); break; case PPPERR_ALLOC: /* Unable to allocate resources. */ logger("ppp_link_status_cb: PPPERR_ALLOC\n"); break; case PPPERR_USER: /* User interrupt. */ logger("ppp_link_status_cb: PPPERR_USER\n"); break; case PPPERR_CONNECT: /* Connection lost. */ logger("ppp_link_status_cb: PPPERR_CONNECT\n"); break; case PPPERR_AUTHFAIL: /* Failed authentication challenge. */ logger("ppp_link_status_cb: PPPERR_AUTHFAIL\n"); break; case PPPERR_PROTOCOL: /* Failed to meet protocol. */ logger("ppp_link_status_cb: PPPERR_PROTOCOL\n"); break; case PPPERR_PEERDEAD: /* Connection timeout. */ logger("ppp_link_status_cb: PPPERR_PEERDEAD\n"); break; case PPPERR_IDLETIMEOUT: /* Idle Timeout. */ logger("ppp_link_status_cb: PPPERR_IDLETIMEOUT\n"); break; case PPPERR_CONNECTTIME: /* PPPERR_CONNECTTIME. */ logger("ppp_link_status_cb: PPPERR_CONNECTTIME\n"); break; case PPPERR_LOOPBACK: /* Connection timeout. */ logger("ppp_link_status_cb: PPPERR_LOOPBACK\n"); break; default: logger("ppp_link_status_cb: unknown errCode %d\n", err_code); break; } } // Callback used by ppp connection static u32_t ppp_output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) { LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(ctx); if (len > 0) { if (!usart_Send(data, len)) return 0x05; } logger("write - ppp_output_cb() len = %d\n", len); return len; } void pppConnect(void) { ppp = pppos_create(&pppos_netif, ppp_output_cb, ppp_link_status_cb, NULL); ppp_set_default(ppp); osThreadId PppGetTaskHandle; osThreadDef(PPP_GET_TASK_NAME, PppGetTask, osPriorityNormal, 0, 128*10); PppGetTaskHandle = osThreadCreate(osThread(PPP_GET_TASK_NAME), NULL); err_t err = ppp_connect(ppp,0); if (err == ERR_ALREADY) { logger("Connected successfully"); } for(int i=0;i<40;i++) { osDelay(500); if (ppp->phase >= PPP_PHASE_RUNNING) break; } } /* USER CODE END 0 */ 

उसके बाद, फ़ंक्शन में MX_LWIP_Init (), ब्लॉक में "/ * USER CODE BEGIN 3 * /" हम pppConnect () फ़ंक्शन में कॉल जोड़ते हैं।

इसके अलावा, आपको ढेर का आकार बढ़ाने की आवश्यकता है, इसके लिए, FreeRTOSConfig.h फ़ाइल में आपको configTOTAL_HEAP_SIZE को परिभाषित करने की आवश्यकता है, और फ़ाइल के अंत में, / * USER CODE BEGIN परिभाषित * / ब्लॉक में, इसे एक नए मान के साथ घोषित करें।

 /* USER CODE BEGIN Defines */ /* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */ #define configTOTAL_HEAP_SIZE ((size_t)1024*30) /* USER CODE END Defines */ 

इसके अलावा, usart.c फ़ाइल में, Q_USART2_SIZE परिभाषा के मान को 2048 में बदलें।

कनेक्शन सेटअप MX_LWIP_Init () फ़ंक्शन के साथ शुरू होता है, यह स्वचालित रूप से बनाया गया था, हमने बस इसमें pppConnect () फ़ंक्शन के लिए एक कॉल जोड़ा था। इस फ़ंक्शन में, PPPOS कनेक्शन परोसने वाले कार्य लॉन्च किए जाते हैं। Pppos_create () फ़ंक्शन को उन फ़ंक्शन के पते पास करने की आवश्यकता होती है जो संदेश भेजने और कनेक्शन कनेक्शन स्थिति के बारे में जानकारी के आउटपुट की सेवा करेंगे। हमारे लिए, ये क्रमशः ppp_output_cb () और ppp_link_status_cb () फ़ंक्शन हैं। इसके अलावा, pppConnect () फ़ंक्शन प्राप्त संदेशों को सर्विस करने का कार्य शुरू करेगा। इसके संचालन के अंत में, pppConnect () फ़ंक्शन सर्वर से कनेक्शन स्थापित करने के लिए प्रतीक्षा करेगा, और फिर अपना ऑपरेशन पूरा करेगा।

नेटवर्क के साथ काम उच्च स्तर पर किया जाएगा, जैसे ही LWIP यह निर्णय लेता है कि नेटवर्क को संदेश भेजना आवश्यक है, ppp_output_cb () फ़ंक्शन को स्वचालित रूप से कहा जाएगा। नेटवर्क से प्रतिक्रिया आने वाले संदेशों को सर्विस करने के कार्य के रूप में PppGetTask () फ़ंक्शन द्वारा प्राप्त की जाएगी, और LWIP के आंत्र में स्थानांतरित की जाएगी। यदि कनेक्शन स्थिति बदल जाती है, तो ppp_link_status_cb () फ़ंक्शन स्वचालित रूप से कहा जाएगा।

अंत में, हम StartDefaultTask कार्य को संशोधित करेंगे। अब इसे इस तरह दिखना चाहिए:

 void StartDefaultTask(void const * argument) { /* init code for LWIP */ // MX_LWIP_Init(); /* USER CODE BEGIN 5 */ usart_Open(); MX_LWIP_Init(); /* Infinite loop */ for(;;) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET); osDelay(1000); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET); osDelay(1000); } /* USER CODE END 5 */ } 

हो गया, आप संकलन और फ्लैश कर सकते हैं।

इस बिंदु पर, आपको पीपीपी सर्वर शुरू करने की आवश्यकता है। ऐसा करने के लिए, आपको पहले लिनक्स के साथ एक वर्चुअल मशीन तैनात करनी होगी। मैंने Ubuntu 16.04 x32 का उपयोग किया। ऑपरेटिंग सिस्टम स्थापित करने के बाद, आपको COM पोर्ट के उपयोग को कॉन्फ़िगर करने की आवश्यकता है।

इस भाग में, हमें विंडोज के साथ वर्चुअल मशीन की आवश्यकता नहीं है, हम इसे सुरक्षित रूप से बंद कर सकते हैं। हम लिनक्स में दोनों FT232 को जोड़ते हैं।

लिनक्स में, इससे पहले कि आप COM पोर्ट के साथ काम करना शुरू करें, आपको उपयोगकर्ता को इसका उपयोग करने की अनुमति देने की आवश्यकता है। ऐसा करने के लिए, निम्नलिखित कमांड निष्पादित करें:

 sudo addgroup USERNAME dialout 

USERNAME वर्तमान उपयोगकर्ता का नाम कहां है।

COM सिस्टम में उपलब्ध पोर्ट देखने के लिए, आपको कमांड चलाने की आवश्यकता है:

 dmesg | grep tty 



हम देखते हैं कि सिस्टम में दो ttyUSB पोर्ट हैं। हम तुरंत नहीं कह सकते हैं कि कौन सा लकड़हारा है और कौन सा usart2 है। आपको बस उन्हें बारी-बारी से जांचना होगा।

सबसे पहले, एक पोर्ट से पढ़ने के लिए कमांड्स निष्पादित करें:

 stty -F /dev/ttyUSB0 115200 cat /dev/ttyUSB0 

फिर दूसरे से:

 stty -F /dev/ttyUSB1 115200 cat /dev/ttyUSB1 

जहां हम ऐसी तस्वीर देखते हैं, वह लकड़हारा है।



आप इस खिड़की को छोड़ सकते हैं, यह हमें परेशान नहीं करेगा।

अगला, आपको हमारे बोर्ड से भेजे गए पैकेट को उनके सबनेट की सीमा को छोड़ने की अनुमति देने की आवश्यकता है। ऐसा करने के लिए, iptables कॉन्फ़िगर करें। हम निम्नलिखित क्रियाएं करते हैं:

1. एक नई कंसोल विंडो खोलें
2. आपको अपना आईपी और नेटवर्क इंटरफेस का नाम पता करने की आवश्यकता है ( ifconfig कमांड चलाएँ)



3. नेट कॉन्फ़िगरेशन कमांड चलाएं

 sudo echo 1 | sudo tee -a /proc/sys/net/ipv4/ip_forward > /dev/null sudo echo 1 | sudo tee -a /proc/sys/net/ipv4/ip_dynaddr > /dev/null sudo iptables -F FORWARD sudo iptables -F -t nat sudo iptables -t nat -A POSTROUTING -o enp0s3 -j SNAT --to-source 192.168.10.196 sudo iptables -t nat -L 

जहाँ enp0s3 नेटवर्क इंटरफ़ेस का नाम है
192.168.10.196 - आपका आईपी पता
/ proc / sys / net / ipv4 / - संबंधित फ़ाइल के लिए पथ।

इन आदेशों को एक बैच फ़ाइल में फिर से लिखा जा सकता है और पीपीपी सर्वर शुरू करने से पहले इसे हर बार चलाया जा सकता है। आप इसे ऑटोरन में जोड़ सकते हैं, लेकिन मैंने नहीं किया।

अब हम सर्वर शुरू करने के लिए तैयार हैं, यह केवल एक सेटिंग फ़ाइल बनाने के लिए बनी हुई है। मैंने इसे " pppd.conf " कहा, मैं निम्नलिखित सेटिंग्स का उपयोग करने का सुझाव देता हूं:

 nodetach noauth passive local debug lock 192.168.250.1:192.168.250.2 /dev/ttyUSB1 115200 lcp-echo-interval 10 lcp-echo-failure 1 cdtrcts 

हम एक फ़ाइल में सेटिंग्स को फिर से लिखते हैं और फिर आप सर्वर शुरू कर सकते हैं। यह sudo pppd फ़ाइल / .ppp.conf कमांड के साथ किया जाता है

पीपीपीडी सर्वर को खोज की शुरुआत से पहले शुरू किया जाना चाहिए, इसलिए पीपीपीडी की शुरुआत के बाद आपको बोर्ड पर स्थित "रीसेट" बटन पर क्लिक करना होगा।

यदि आपने सब कुछ सही ढंग से किया है, तो आप निम्नलिखित चित्र देखेंगे:



बाईं ओर pppd चल रहा है, दाईं ओर लकड़हारा है।

स्टेज 4. हम एक बैग भेजते हैं


इस स्तर पर, हम दोनों आभासी मशीनों की जरूरत है। पैकेज प्राप्त करने के लिए pppd और Windows के लिए लिनक्स। कार्य को सरल बनाने के लिए, यह आवश्यक है कि दोनों मशीनें एक ही सबनेट पर हों, आदर्श समाधान वर्चुअलबॉक्स नेटवर्क सेटिंग्स में दोनों मशीनों के लिए नेटवर्क ब्रिज कनेक्शन निर्दिष्ट करने और विंडोज में फ़ायरवॉल को अक्षम करने के लिए होगा।

हम वर्चुअल मशीन शुरू करते हैं और डिस्कवरी बोर्ड के पीपीपी कनेक्शन को pppd से कॉन्फ़िगर करते हैं। विंडोज पर, हमें मशीन का आईपी पता (ipconfig कमांड) पता चला, मुझे यह 192.168.10.97 मिला।

पैकेट प्रेषक लॉन्च करें और इसे निम्नानुसार कॉन्फ़िगर करें:



अब फिर से, Main.c फ़ाइल में StartDefaultTask कार्य को संशोधित करें।

 /* USER CODE BEGIN 4 */ #include "logger.h" #include "sockets.h" typedef uint32_t SOCKET; /* USER CODE END 4 */ /* StartDefaultTask function */ void StartDefaultTask(void const * argument) { /* init code for LWIP */ // MX_LWIP_Init(); /* USER CODE BEGIN 5 */ usart_Open(); MX_LWIP_Init(); /* Infinite loop */ uint8_t sendStr[]="Test message TCP/IP."; uint8_t resvStr[100]={0}; int resvLength = 0; struct sockaddr_in sockAddr; sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons( 6565 ); uint32_t addr = inet_addr("192.168.10.97"); sockAddr.sin_addr.s_addr = addr; SOCKET socket = NULL; int nError = 0; /* Infinite loop */ for(;;) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET); osDelay(1000); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET); osDelay(1000); socket = socket( AF_INET, SOCK_STREAM, 0 ); nError = connect( socket, (struct sockaddr*)&sockAddr, sizeof(sockAddr) ); if ( nError == 0 ) { nError = send( socket, sendStr, sizeof(sendStr)-1, 0 ); if ( nError < 0 ) logger("SEND ERROR %d\n", nError); else { logger("SEND - %s\n", sendStr); resvLength = 0; while(resvLength < 1) resvLength = lwip_recv( socket, resvStr, sizeof(resvStr), MSG_WAITALL); resvStr[resvLength]=0; logger("GET - %s\n", resvStr); } lwip_close(socket); } else logger("CONNECT ERROR %d\n", nError); } /* USER CODE END 5 */ } 

एड्र चर के मूल्य के रूप में, हम विंडोज मशीन के पते का उपयोग करते हैं, पोर्ट संख्या 6565।
भेजा गया संदेश "परीक्षण संदेश टीसीपी / आईपी।", प्रतिक्रिया "संदेश प्राप्त होता है।"

यहां आप देख सकते हैं कि संदेश भेजने और प्राप्त करने के लिए पीपीपी फ़ंक्शन का सीधे उपयोग नहीं किया जाता है। सभी कार्य उच्च स्तर पर होते हैं, और हमारे कार्यों को स्वचालित रूप से कहा जाता है।

हम संकलन और फ्लैश करते हैं।

Pppd से कनेक्ट करने का परिणाम लिनक्स मशीन पर दिखाई देता है:



प्राप्त अनुरोध और भेजी गई प्रतिक्रियाएं पैकेट भेजने वाले प्रोग्राम में विंडोज मशीन पर देखी जा सकती हैं:



खैर, यह सब, डिस्कवरी बोर्ड से भेजा गया पैकेट, हम COM पोर्ट पर गया, pppd सर्वर को मिला, मशीन के विंडोज पोर्ट 6565 पर भेजा गया, वहां इसे सफलतापूर्वक प्राप्त किया गया, इसके जवाब में एक और पैकेट भेजा गया - इसे पास किया गया। विपरीत दिशा में रास्ता और बोर्ड पर सफलतापूर्वक अपनाया गया था। आप इंटरनेट पर किसी भी मशीन को संदेश भेजने में सक्षम हो सकते हैं।

→ पूर्ण परियोजना कोड यहां डाउनलोड किया जा सकता है

Source: https://habr.com/ru/post/hi419037/


All Articles