کار با ماژول تمام عیار mc60 – قسمت دوم – راه اندازی OpenCPU

0
944
کار با ماژول تمام عیار mc60 – قسمت دوم – راه اندازی OpenCPU

در قسمت اول به یکسری اطلاعات کلی ماژول mc60 پرداختیم، با نرم افزار QNavigator کار کردیم و یک هدربرد هم برای کار با ماژول معرفی کردیم. توی این قسمت میخوایم از قابلیت هیجان انگیز OpenCpu ماژول mc60 استفاده کنیم تا پیامک‌های دریافتی رو بخونیم و بر اساس آن کدهایی رو اجرا کنیم. در نهایت هم نتیجه رو به فرستنده پیامک می‌کنیم!

در این آموزش با ما همراه باشید.

 

برای راه اندازی ماژول mc60 به صورت OpenCpu شرکت کوئیکتل دو راه پیشنهاد داده که یکی استفاده از Eclipse IDE برای ویرایش کدها و کامپایل کردن، و دیگری ویرایش کدها با یک ادیتور و کامپایل کردن به صورت دستی هست. اما حالا ما میایم و از ویرایشگر Visual Studio Code استفاده می‌کنیم.

در مرحله اول vs code رو نصب می‌کنیم.

سپس کامپایلر GCC رو نصب می‌کنیم که فایل نصبی اون در پیوست موجود هست (به همراه راهنمای نصب).

بعد از نصب، از SDK که برای کار با ماژول آماده شده استفاده می‌کنیم و پوشه اون رو در vs code باز می‌کنیم. (SDK در پیوست موجود هست)

برای این کار از از منوی file-> open folder استفاده می‌کنیم.

file-> open folder

حالا به کاربرد برخی فایل‌ها و پوشه‌های موجود در sdk می‌پردازیم:

build/gcc: محل ذخیره فریمور تولید شده

custom/main.c: کدهای اصلی ماژول

docs: فایل‌های راهنمای ماژول

example: نمونه کد برای کار با بخش‌های مختلف ماژول

برای شروع فایل main.c رو به صورت زیر تغییر میدیم تا یک چشمک زن ساده داشته باشیم.

 

#ifdef __CUSTOMER_CODE__

#include "ql_system.h"
#include "ql_gpio.h"


void proc_main_task(s32 taskId)
{
// Specify a GPIO pin
Enum_PinName gpioPin = PINNAME_NETLIGHT;

// Initialize the GPIO pin (output high level, pull up)
Ql_GPIO_Init(gpioPin, PINDIRECTION_OUT, PINLEVEL_HIGH, PINPULLSEL_PULLUP);
while (TRUE)
{
// Set the GPIO level to low after 500ms.
Ql_Sleep(500);
Ql_GPIO_SetLevel(gpioPin, PINLEVEL_LOW);

// Set the GPIO level to high after 500ms.
Ql_Sleep(500);
Ql_GPIO_SetLevel(gpioPin, PINLEVEL_HIGH);
}
}

#endif

 

تابع proc_main_task تابع شروع برناممون هست

و تابع Ql_Sleep برای تأخیر بر اساس ms هست.

 

حالا برای کامپایل باید داخل پوشه اصلی sdk خودمون یک دستور رو توسط کامند اجرا کنیم. برای این کار میتونید cmd رو باز کرده و به پوشه sdk بیایید یا اینکه فایل MS-DOS رو باز کنید تا cmd در همون پوشه بالا بیاد، حالا دستور

make clean && make new

 

رو اجرا می‌کنیم.

 

اگر که با این پیغام مواجه شدید:

...
- Building build\gcc\obj/custom/fota/src/fota_http.o
- Building build\gcc\obj/custom/fota/src/fota_http_code.o
- Building build\gcc\obj/custom/fota/src/fota_main.o
----------------------------------------------------
- GCC Compiling Finished Sucessfully.
- The target image is in the 'build\gcc' directory.
----------------------------------------------------

 

یعنی که هیچ مشکلی وجود نداره!

اما اگر چنین پیغامی نداد یعنی در کد هاتون مشکل دارید. برای پیدا کردن مشکل به فایل build\gcc\build.log مراجعه کرده و ارور مربوطه رو پیدا کنید، به طور مثال این پیغام

...
example/utility.c:120:17: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
custom/main.c: In function 'proc_main_task':
custom/main.c:14:5: error: expected ',' or ';' before 'Ql_GPIO_Init'
make.exe[1]: *** [build\gcc\obj/custom/main.o] Error 1
make: *** [all] Error 2

 

نشون دهنده نگذاشتن سمی کالن قبل خط 14 هست.

خب حالا کد ما به درستی کامپایل شده. تغذیه ماژول رو متصل کرده و پورت UART اون رو با یک رابط سریال به سیستم متصل می‌کنیم.

 

برای آپلود کردن فریمور از نرم افزار QFlash استفاده می‌کنیم. (این نرم افزار رو میتونید در پیوست همین مطلب دانلود کنید.)

QFlash

 

از بخش 1 فایل app_image_bin.cfg رو از مسیر \build\gcc انتخاب کرده

و در بخش 2 نوع ماژول رو انتخاب می‌کنیم و از بخش 3 پورتی که به ماژول متصل هست انتخاب و گزینه استارت رو می‌زنیم.

 

هنگام نمایش پیغام Waiting…… یک بار ماژول رو خاموش روشن می‌کنیم و بعد پیغام Download … نمایش داده میشه که بعد حدود 35 ثانیه باید این پیغام نمایش داده به شه که نشون دهنده آپلود موفقیت آمیز هست.

QFlash

بعد یک بار تغذیه ماژول رو قطع و وصل کرده و شاهد چشمک زدن LED روی پایه 47 (NETLIGHT) هستیم.

 

حالا که اولین تستمون رو گرفتیم میریم سراغ کد نویسی به طور کامل‌تر.

برای راه اندازی OpenCpu ماژول MC60 و استفاده از سخت افزارهای ماژول، همچنین کد نویسی راحت‌تر یکسری توابع توسط خود شرکت Quectel تهیه شده که فایلش در پیوست با نام OpenCPU_User_Guide موجود هست، همچنین میتونیم از example های خود sdk استفاده کنیم، اما ما در این قسمت یک برنامه ساده که با دریافت یک sms یک فعالیت ساده انجام داده و نتیجه اون رو ارسال می کنه شروع می‌کنیم.

کدهای ما به این صورت است:

#ifdef __CUSTOMER_CODE__
#include "ril.h"
#include "ril_util.h"
#include "ril_sms.h"
#include "ril_telephony.h"
#include "ril_system.h"
#include "ql_stdlib.h"
#include "ql_error.h"
#include "ql_trace.h"
#include "ql_uart.h"
#include "ql_system.h"
#include "ql_memory.h"
#include "ql_timer.h"
#include "ql_gpio.h"

#if (defined(__OCPU_RIL_SUPPORT__) && defined(__OCPU_RIL_SMS_SUPPORT__))
char PhNum[] = "+98912XXXXXXX\0";
static char DBG_BUFFER[512];
#define CON_SMS_BUF_MAX_CNT (1)
#define APP_DEBUG(FORMAT, ...) \
{ \
Ql_memset(DBG_BUFFER, 0, 512); \
Ql_sprintf(DBG_BUFFER, FORMAT, ##__VA_ARGS__); \
Ql_UART_Write((Enum_SerialPort)(UART_PORT1), (u8 *)(DBG_BUFFER), Ql_strlen((const char *)(DBG_BUFFER))); \
}
typedef struct
{
u16 uMsgRef;
} ConSMSStruct;

ConSMSStruct g_asConSMSBuf[CON_SMS_BUF_MAX_CNT];

static bool ConSMSBuf_ResetCtx(ConSMSStruct *pCSBuf, u8 uCSMaxCnt, u8 uIdx)
{
Ql_memset(&pCSBuf[uIdx], 0x00, sizeof(ConSMSStruct));
return TRUE;
}

void SMS_TextMode_Send(char strPhNum[], char strTextMsg[])
{
u32 nMsgRef;
ST_RIL_SMS_SendExt sExt;
Ql_memset(&sExt, 0x00, sizeof(sExt));
APP_DEBUG("< Send Normal Text SMS begin... >\r\n");
RIL_SMS_SendSMS_Text(strPhNum, Ql_strlen(strPhNum), LIB_SMS_CHARSET_GSM, strTextMsg, Ql_strlen(strTextMsg), &nMsgRef);
}

static void Hdlr_RecvNewSMS(u32 nIndex, bool bAutoReply)
{
ST_RIL_SMS_TextInfo *pTextInfo = NULL;
ST_RIL_SMS_DeliverParam *pDeliverTextInfo = NULL;
char aPhNum[RIL_SMS_PHONE_NUMBER_MAX_LEN] = {
0,
};
pTextInfo = Ql_MEM_Alloc(sizeof(ST_RIL_SMS_TextInfo));
Ql_memset(pTextInfo, 0x00, sizeof(ST_RIL_SMS_TextInfo));
RIL_SMS_ReadSMS_Text(nIndex, LIB_SMS_CHARSET_GSM, pTextInfo);
pDeliverTextInfo = &((pTextInfo->param).deliverParam);

Ql_strcpy(aPhNum, pDeliverTextInfo->oa);
APP_DEBUG("data = %s\r\n", (pDeliverTextInfo->data));
char text[350];
Ql_strcpy(text, (pDeliverTextInfo->data));


if (text[0] == 'p' && text[1] == 'i' && text[2] == 'n')
{
switch (text[4])
{
case '1':
Ql_GPIO_Init(PINNAME_NETLIGHT, PINDIRECTION_OUT, 0, PINPULLSEL_PULLUP);
if (text[6] == 'o' && text[7] == 'n')
{
Ql_GPIO_SetLevel(PINNAME_NETLIGHT, 1);
}
else if (text[6] == 'o' && text[7] == 'f' && text[8] == 'f')
{
Ql_GPIO_SetLevel(PINNAME_NETLIGHT, 0);
}
break;
}
if (bAutoReply)
{
SMS_TextMode_Send(aPhNum, "OK\0");
}
}
Ql_MEM_Free(pTextInfo);

return;
}

static void CallBack_UART_Hdlr(Enum_SerialPort port, Enum_UARTEventType msg, bool level, void *customizedPara) {}

void proc_main_task(s32 iTaskID)
{
ST_MSG taskMsg;

//Register & open UART port
Ql_UART_Register(UART_PORT1, CallBack_UART_Hdlr, NULL);
Ql_UART_Open(UART_PORT1, 115200, FC_NONE);

APP_DEBUG("Sisoog MC60 SMS Example\r\n");
while (TRUE)
{
s32 i = 0;

Ql_memset(&taskMsg, 0x0, sizeof(ST_MSG));
Ql_OS_GetMessage(&taskMsg);
switch (taskMsg.message)
{
case MSG_ID_RIL_READY:
{
APP_DEBUG("<-- RIL is ready -->\r\n");
Ql_RIL_Initialize(); // MUST call this function
for (i = 0; i < CON_SMS_BUF_MAX_CNT; i++)
{
ConSMSBuf_ResetCtx(g_asConSMSBuf, CON_SMS_BUF_MAX_CNT, i);
}
break;
}
case MSG_ID_URC_INDICATION:
switch (taskMsg.param1)
{
case URC_SYS_INIT_STATE_IND:
{
if (SYS_STATE_SMSOK == taskMsg.param2)
{
RIL_SMS_DeleteSMS(0, RIL_SMS_DEL_ALL_MSG);
SMS_TextMode_Send(PhNum, "Module is ON\0");
APP_DEBUG("\r\n READY \r\n", taskMsg.param2);
}
break;
}
case URC_SIM_CARD_STATE_IND:
{
APP_DEBUG("\r\n<-- SIM Card Status:%d -->\r\n", taskMsg.param2);
}
break;

case URC_GSM_NW_STATE_IND:
{
APP_DEBUG("\r\n<-- GSM Network Status:%d -->\r\n", taskMsg.param2);
break;
}

case URC_NEW_SMS_IND:
{
APP_DEBUG("\r\n<-- New SMS Arrives: index=%d\r\n", taskMsg.param2);
Hdlr_RecvNewSMS((taskMsg.param2), TRUE);
break;
}
}
break;
}
}
}
#endif // __OCPU_RIL_SUPPORT__ && __OCPU_RIL_SMS_SUPPORT__
#endif // __CUSTOMER_CODE__

 

خوب، حالا به تشریح کدها می‌پردازیم:

در تابع proc_main_task

ابتدا پورت UART اصلی رو به عنوان دیباگ استفاده می‌کنیم و وضعیت ماژول رو در اون چاپ می‌کنیم:

 Ql_UART_Register(UART_PORT1, CallBack_UART_Hdlr, NULL);
Ql_UART_Open(UART_PORT1, ۱۱۵۲۰۰, FC_NONE);

سپس در یک حلقه While پیغام‌هایی که از هسته ماژول میاد رو بررسی می‌کنیم، ما از یک switch case استفاده کرده و مطابق با پیغام‌های دریافتی میتونیم کدهایی رو اجرا کنیم.

 

مهم‌ترین بخش RIL هست که کار AT_COMMAND ها رو برای ما انجام می‌ده و توسط توابعی که RIL داره میتونیم از امکانات ماژول استفاده کنیم.

 while (TRUE)
{
s32 i = ۰;

Ql_memset(&taskMsg, 0x0, sizeof(ST_MSG));
Ql_OS_GetMessage(&taskMsg);
switch (taskMsg.message)
{
case MSG_ID_RIL_READY:
{

 

در خط 121 تا 133 آماده بودن امکان SMS رو بررسی کرده و در صورت آماده بودن یک پیام توسط تابع SMS_TextMode_Send ارسال می‌کنیم که مقدار اول اون شماره‌ای که باید پیام به اون ارسال به شه (تعریف شده در خط 17) و مقدار دوم متن پیام هست.

 case MSG_ID_URC_INDICATION:
switch (taskMsg.param1)
{
case URC_SYS_INIT_STATE_IND:
{
if (SYS_STATE_SMSOK == taskMsg.param2)
{
RIL_SMS_DeleteSMS(۰, RIL_SMS_DEL_ALL_MSG);
SMS_TextMode_Send(PhNum, "Module is ON\0");
APP_DEBUG("\r\n READY \r\n", taskMsg.param2);
}
break;
}

 

در خط 146 تا 151 دریافت پیام جدید رو بررسی می‌کنیم و در صورت وجود تابع Hdlr_RecvNewSMS رو صدا زده و در پارامتر اول اطلاعات پیام رو ارسال کرده و در پارامتر دوم مشخص می‌کنیم که پیامک تأیید دریافت برای فرستنده ارسال بشه یا نه

 case URC_NEW_SMS_IND:
{
APP_DEBUG("\r\n<-- New SMS Arrives: index=%d\r\n", taskMsg.param2);
Hdlr_RecvNewSMS((taskMsg.param2), TRUE);
break;
}

 

سپس در خط 66 تا 86 به بررسی پیام دریافتی می‌پردازیم و اگر پیام pin 1 on دریافت شده بود NETLIGHT روشن شده و اگر pin 1 off دریافت شده بود خاموش می‌شود.
سپس اگر ارسال پیامک تأیید فعال بود یک پیامک به شماره‌ای که از آن دستور دریافت شده بود با متن OK ارسال می‌شود.

 if (text[۰] == 'p' && text[1] == 'i' && text[2] == 'n')
{
switch (text[4])
{
case '1':
Ql_GPIO_Init(PINNAME_NETLIGHT, PINDIRECTION_OUT, 0, PINPULLSEL_PULLUP);
if (text[۶] == 'o' && text[7] == 'n')
{
Ql_GPIO_SetLevel(PINNAME_NETLIGHT, 1);
}
else if (text[۶] == 'o' && text[7] == 'f' && text[8] == 'f')
{
Ql_GPIO_SetLevel(PINNAME_NETLIGHT, 0);
}
break;
}
if (bAutoReply)
{
SMS_TextMode_Send(aPhNum, "OK\0");
}
}

 

کار با بخش پیامک به طور کامل‌تر در بخش example های sdk موجود هست و می‌توانید استفاده کنید.

 

توی قسمت بعد سراغ کار با بخش GPS ماژول رفته و اطلاعات مکانی رو به یک سرور ارسال می‌کنیم و مکان اون رو در یک نقشه گوگل نمایش می‌دهیم، پس قسمت‌های بعدی آموزش رو هم دنبال کنید.

لازم به ذکر هست که خود شرکت کویکتل با استفاده از ادیتور Eclipse این قابلیت اپن سی پی یو را راه اندازی کرده و کلیه داکیومنت ها و حتی نسخه Eclipse مربوطه نیز درون فایل دانلودی پایین بصورت کامل در دسترس هست.

 

پیوست – لینک‌های دانلود
لینک دانلود مستقیم “کامپایلر GCC – ماژول MC60 – نرم افزار QFlash  Eclipse” – حجم 808 مگابایت
اسم فایل:
MC60 OpenCPU .rar

 

 

در این قسمت میتونید به همه قسمت‌های سری آموزش های ماژول mc60 دسترسی پیدا کنید:
کار با ماژول تمام عیار mc60 – قسمت اول – برد راه انداز
کار با ماژول تمام عیار mc60 – قسمت دوم – راه اندازی OpenCPU
کار با ماژول تمام عیار mc60 – قسمت سوم – ساخت ردیاب
کار با ماژول تمام عیار mc60 – قسمت چهارم – OpenCPU و تکمیل ردیاب
کار با ماژول تمام عیار mc60 – قسمت پنجم – ساخت MP3 Player
کار با ماژول تمام عیار mc60 – قسمت ششم – نمایشگر oled

 

 

 

منبع:سیسوگ

مطلب قبلیاصلاح ویدیو -آموزش پردازش تصویر در پایتون – جلسه 14: تشخیص الگوهای مشابه
مطلب بعدیابزار Arduino CLI – آنچه یک آردوینو نویس حرفه ای به آن احتیاج دارد!

پاسخ دهید

لطفا نظر خود را وارد کنید!
لطفا نام خود را در اینجا وارد کنید