Helper library to use modem_ref driver.
Dependencies: WizziCom WizziDebug ram_fs modem_ref
Dependents: D7A_Localisation D7A_1x_demo_send_file_data_and_forget D7A_1x_demo_CodeUpgradeProtocol D7A_1x_demo_LoRaWAN ... more
modem_d7a.cpp
- Committer:
- Jeej
- Date:
- 2021-09-21
- Revision:
- 76:cbe558f136a4
- Parent:
- 75:dad2f09cb870
- Child:
- 77:5146f44cde83
File content as of revision 76:cbe558f136a4:
#include "mbed.h" #include "modem_d7a.h" #include "modem_cup.h" #if 0 #define HELPER_PRINT(...) PRINT(__VA_ARGS__) #else #define HELPER_PRINT(...); #endif #define MODEM_VERSION_MAJOR 5 #define MODEM_VERSION_MINOR 6 #define MODEM_VERSION_PATCH 0 #define MODEM_DEVICE_ID 0x00001001 Semaphore g_s[MAX_USER_NB]; static WizziCom* g_modem_com; // Callback for id User static void modem_cb(uint8_t terminal, int8_t err, uint8_t id) { (void)id; //PRINT("CB EOP:%d ERR:%d ID:%d\n", terminal, err, id); if (terminal) { g_s[id].release(); } } static int g_boot_nb; static int g_read_nb; static int g_swr_nb; static int g_hwr_nb; static int g_pwc_nb; static int g_fail_nb; int modem_wait_resp(Semaphore* s, uint32_t timeout, char* function, uint32_t line) { if (!s->try_acquire_for(timeout)) { PRINT("%s:%d: Modem resp timeout after %d ms\n", function, line, timeout); return -1; } return 0; } int my_alp_itf_d7a_cfg_size(d7a_sp_cfg_t* cfg) { int size = sizeof(d7a_sp_cfg_t) - sizeof(d7a_addressee_t); size += D7A_ADDR_LEN(cfg->addressee.ctrl); return size; } // ============================================================}}} // Serial adapters to WizziLab's own architecture // ============================================================{{{ static void modem_serial_input(WizziCom* com, WizziComPacket_t* pkt) { modem_ref_input(wizzicom_type_to_flow(pkt->type), pkt->data, pkt->length); } static int modem_serial_send(uint8_t type, uint8_t* data, uint8_t size) { // Retrieve Flow ID from header and send packet g_modem_com->send((WizziComPacketType)type, size, data); return size; } static Semaphore boot(0); void my_startup_boot(u8 cause, u16 number) { HELPER_PRINT("Modem BOOT[%c] #%d\r\n", cause, number); boot.release(); } int modem_open(modem_ref_callbacks_t* callbacks) { static union { uint8_t b[8]; uint32_t w[2]; } uid; revision_t rev; int err; //for (int i = 0; i < MAX_USER_NB; i++) //{ //g_s[i] = Semaphore(0); //} g_boot_nb++; // Override boot callback to catch the first boot message modem_ref_callbacks_t boot_callbacks = { .read = NULL, .write = NULL, .read_fprop = NULL, .flush = NULL, .remove = NULL, .udata = NULL, .lqual = NULL, .ldown = NULL, .reset = NULL, .boot = my_startup_boot, .busy = NULL, .itf_busy = NULL, }; // Open modem Com port g_modem_com = new WizziCom(MODEM_PIN_RX, MODEM_PIN_TX, MODEM_PIN_IRQ_IN, MODEM_PIN_IRQ_OUT); // open with user callbacks modem_ref_open(modem_serial_send, callbacks); // Redirect All Port traffic to modem_serial_input g_modem_com->attach(modem_serial_input, WizziComPacketUntreated); // Wait for modem power up ThisThread::sleep_for(100); // Try reading UID err = modem_read_file(D7A_FID_UID, uid.b, 0, 8); if (ALP_ERR_NONE > err) { PRINT("Trying software reset...\n"); // Open driver to catch boot packet modem_ref_close(); modem_ref_open(NULL, &boot_callbacks); // Try software reset g_modem_com->send(WizziComPacketSysReset, 0, NULL); if (!boot.try_acquire_for(1000)) { PRINT("Trying hardware reset...\n"); // Assert reset pin DigitalOut reset_low(MODEM_PIN_RESET, 0); ThisThread::sleep_for(100); // Release reset pin DigitalIn reset_release(MODEM_PIN_RESET); if (!boot.try_acquire_for(1000)) { #if 0 // Modem not responding! PRINT("Trying power cycle.\n"); // Assert power pin DigitalOut power_high(D12, 1); ThisThread::sleep_for(1000); // Release reset pin DigitalIn power_release(D12); if (boot.try_acquire_for(1000)) { g_pwc_nb++; PRINT("Modem is up after power cycle.\n"); } else #endif { // Modem not responding! g_fail_nb++; PRINT("Failed to open modem.\n"); return -1; } } else { g_hwr_nb++; PRINT("Modem is up after hardware reset.\n"); } } else { g_swr_nb++; PRINT("Modem is up after software reset.\n"); } // Re-open with user callbacks modem_ref_close(); modem_ref_open(modem_serial_send, callbacks); } else { g_read_nb++; PRINT("Modem is up.\n"); } PRINT("Boot stats: boot:%d read:%d swr:%d hwr:%d pwc:%d fail:%d\n", g_boot_nb, g_read_nb, g_swr_nb, g_hwr_nb, g_pwc_nb, g_fail_nb); ThisThread::sleep_for(100); modem_read_file(D7A_FID_UID, uid.b, 0, 8); modem_read_file(D7A_FID_FIRMWARE_VERSION, (uint8_t*)&rev, 0, sizeof(revision_t)); PRINT("------------ D7A Modem infos ------------\r\n"); PRINT_DATA(" - UID: ", "%02X", uid.b, 8, "\r\n"); PRINT(" - Manufacturer ID: %08X\r\n", rev.manufacturer_id); PRINT(" - Device ID: %08X\r\n", rev.device_id); PRINT(" - Hardware version: %08X\r\n", rev.hw_version); PRINT(" - Firmware version: v%d.%d.%d [%02X]\r\n", rev.fw_version.major, rev.fw_version.minor, rev.fw_version.patch, rev.fw_version.id); PRINT(" - CUP max size: %d\r\n", rev.cup_max_size); PRINT("-----------------------------------------\r\n"); FLUSH(); //modem_cup_update(&rev); return 0; } int modem_close(void) { modem_ref_close(); delete g_modem_com; return 0; } static int _modem_d7a_send(void* itf, alp_payload_t* alp, alp_payload_t** alp_rsp, uint32_t timeout) { u8 id = modem_ref_get_id(modem_cb); int err = ALP_ERR_UNKNOWN; // Make sure Semaphore is taken g_s[id].try_acquire(); modem_ref_alp(itf, alp, alp_rsp, id); if (!g_s[id].try_acquire_for(timeout)) { err = ALP_ERR_UNKNOWN; } else { err = ALP_ERR_NONE; } modem_ref_free_id(id); return err; } static int _modem_get_istatus(alp_payload_t* alp, void* istatus) { alp_payload_t* alp_tmp = alp_payload_get(alp, ALP_OPCODE_RSP_ISTATUS); if (alp_tmp) { alp_parsed_chunk_t r; u8* p = alp_tmp->d; alp_parse_chunk(&p, &r); memcpy(istatus, r.data, r.meta.itf.length); return ALP_ERR_NONE; } else { PRINT("No metadata\n"); } return ALP_ERR_UNKNOWN; } int modem_raw_alp(alp_payload_t* alp, alp_payload_t** alp_rsp) { return _modem_d7a_send(NULL, alp, alp_rsp, MODEM_TIMEOUT_LOCAL); } int modem_remote_raw_alp(void* itf, alp_payload_t* alp, alp_payload_t** alp_rsp) { return _modem_d7a_send(itf, alp, alp_rsp, MODEM_TIMEOUT_DISTANT); } static int _modem_send_alp(void* itf, void *istatus, alp_payload_t* alp, uint32_t timeout) { int err = ALP_ERR_UNKNOWN; alp_payload_t* alp_rsp = NULL; err = _modem_d7a_send(itf, alp, &alp_rsp, timeout); do { if (ALP_ERR_NONE > err) { PRINT("Send ALP timeout\n"); break; } err = alp_payload_get_err(alp_rsp); if (ALP_ERR_NONE > err) { PRINT("Send ALP err %d\n", err); break; } if (istatus) { _modem_get_istatus(alp_rsp, istatus); } } while (0); alp_payload_free(alp_rsp); return err; } static int _modem_read_file(uint8_t* itf, void *istatus, uint8_t fid, void *data, uint32_t offset, uint32_t length, uint32_t timeout) { int err = ALP_ERR_UNKNOWN; alp_payload_t* alp = NULL; alp_payload_t* alp_rsp = NULL; alp = alp_payload_f_rd_data(NULL, fid, offset, length, false); err = _modem_d7a_send(NULL, alp, &alp_rsp, timeout); do { if (ALP_ERR_NONE > err) { PRINT("Read file timeout\n"); break; } err = alp_payload_get_err(alp_rsp); if (ALP_ERR_NONE > err) { PRINT("Read file err %d\n", err); break; } alp = alp_payload_get(alp_rsp, ALP_OPCODE_RSP_F_DATA); if (alp) { alp_parsed_chunk_t r; u8* p = alp->d; alp_parse_chunk(&p, &r); memcpy(data, r.data, r.meta.f_data.length); } else { PRINT("Read file no payload\n"); err = ALP_ERR_UNKNOWN; break; } if (istatus) { _modem_get_istatus(alp_rsp, istatus); } } while (0); alp_payload_free(alp_rsp); return err; } int modem_read_file(uint8_t fid, void *data, uint32_t offset, uint32_t length) { return _modem_read_file(NULL, NULL, fid, data, offset, length, MODEM_TIMEOUT_LOCAL); } int modem_remote_read_file(uint8_t* itf, void *istatus, uint8_t fid, void *data, uint32_t offset, uint32_t length) { return _modem_read_file(itf, istatus, fid, data, offset, length, MODEM_TIMEOUT_DISTANT); } int modem_write_file(uint8_t fid, void *data, uint32_t offset, uint32_t length) { alp_payload_t* alp = alp_payload_f_wr_data(NULL, fid, data, offset, length, false); return _modem_send_alp(NULL, NULL, alp, MODEM_TIMEOUT_LOCAL); } int modem_remote_write_file(uint8_t* itf, void *istatus , uint8_t fid, void *data, uint32_t offset, uint32_t length) { alp_payload_t* alp = alp_payload_f_wr_data(NULL, fid, data, offset, length, false); return _modem_send_alp(itf, istatus, alp, MODEM_TIMEOUT_DISTANT); } int modem_flush_file(uint8_t fid) { alp_payload_t* alp = alp_payload_f_flush(NULL, fid, false); return _modem_send_alp(NULL, NULL, alp, MODEM_TIMEOUT_LOCAL); } int modem_declare_file(uint8_t fid, alp_file_header_t* header) { alp_payload_t* alp = alp_payload_f_declare(NULL, fid, header); return _modem_send_alp(NULL, NULL, alp, MODEM_TIMEOUT_LOCAL); } int modem_notify_file(uint8_t fid, uint32_t offset, uint32_t length) { alp_payload_t* alp = alp_payload_f_touch(NULL, fid, offset, length, false); return _modem_send_alp(NULL, NULL, alp, MODEM_TIMEOUT_LOCAL); } static int _modem_d7a_itf_enable(u8 enable) { alp_payload_t* alp = alp_payload_activate_itf(NULL, ALP_ITF_TYPE_D7A, 24, 0, ALP_D7A_ISTAT_RESP | ALP_D7A_ISTAT_UNS | ALP_D7A_ISTAT_EOP, enable); return _modem_send_alp(NULL, NULL, alp, MODEM_TIMEOUT_LOCAL); } int modem_d7a_enable_itf(void) { return _modem_d7a_itf_enable(true); } int modem_d7a_disable_itf(void) { return _modem_d7a_itf_enable(false); } static int modem_lwan_set_urc(void) { alp_payload_t* alp = alp_payload_urcc_en(NULL, ALP_URC_TYPE_ITF_BUSY, FID_LWAN_ITF, 1); return _modem_send_alp(NULL, NULL, alp, MODEM_TIMEOUT_LOCAL); } static int modem_lwan_enable_itf(void) { alp_payload_t* alp = alp_payload_activate_itf(NULL, ALP_ITF_TYPE_LWAN, 1, FID_LWAN_ITF, 0, true); return _modem_send_alp(NULL, NULL, alp, MODEM_TIMEOUT_LOCAL); } int modem_lwan_open(modem_lwan_callbacks_t* callbacks) { int err = ALP_ERR_UNKNOWN; modem_ref_set_lwan_cb(callbacks); err = modem_lwan_set_urc(); if (ALP_ERR_NONE > err) { return err; } err = modem_lwan_enable_itf(); return err; } int modem_lwan_set_cfg(lwan_cfg_t* cfg) { return modem_write_file(FID_LWAN_CFG, cfg, 0, sizeof(lwan_cfg_t)); } int modem_lwan_set_nls(lwan_nls_t* nls) { return modem_write_file(FID_LWAN_NLS, nls, 0, sizeof(lwan_nls_t)); } int modem_lwan_send(alp_payload_t* alp) { alp_itf_lwan_cfg_t itf = { .type = ALP_ITF_TYPE_LWAN }; return _modem_d7a_send((void*)&itf, alp, NULL, MODEM_TIMEOUT_DISTANT); } int modem_lwan_get_status(lwan_status_t* status) { return modem_read_file(FID_LWAN_STATUS, status, 0, sizeof(lwan_status_t)); } void modem_print_error(uint8_t itf, int error) { if (ALP_ERR_ITF_START >= error && ALP_ERR_ITF_END < error) { error -= ALP_ERR_ITF_START; // Interface specific error if (ALP_ITF_TYPE_HOST == itf) { PRINT("ITF[%02X] Error %d\r\n", itf, error); } else if (ALP_ITF_TYPE_COM == itf) { PRINT("ITF[%02X] Error %d\r\n", itf, error); } else if (ALP_ITF_TYPE_D7A == itf) { PRINT("ITF[%02X] ", itf); switch (error) { /// No error case D7A_ERROR_NO: // = 0, PRINT("D7A_ERROR_NO\r\n"); break; /// Resource busy case D7A_ERROR_BUSY: // = -1, PRINT("D7A_ERROR_BUSY\r\n"); break; /// Bad parameter case D7A_ERROR_BAD_PARAM: // = -2, PRINT("D7A_ERROR_BAD_PARAM\r\n"); break; /// Duty cycle limit overflow case D7A_ERROR_DUTY_CYCLE: // = -3, PRINT("D7A_ERROR_DUTY_CYCLE\r\n"); break; /// CCA timeout case D7A_ERROR_CCA_TO: // = -4, PRINT("D7A_ERROR_CCA_TO\r\n"); break; /// Security frame counter overflow case D7A_ERROR_NLS_KEY: // = -5, PRINT("D7A_ERROR_NLS_KEY\r\n"); break; /// TX stream underflow case D7A_ERROR_TX_UDF: // = -6, PRINT("D7A_ERROR_TX_UDF\r\n"); break; /// RX stream overflow case D7A_ERROR_RX_OVF: // = -7, PRINT("D7A_ERROR_RX_OVF\r\n"); break; /// RX checksum case D7A_ERROR_RX_CRC: // = -8, PRINT("D7A_ERROR_RX_CRC\r\n"); break; /// Abort case D7A_ERROR_ABORT: // = -9, PRINT("D7A_ERROR_ABORT\r\n"); break; /// No ACK received case D7A_ERROR_NO_ACK: // = -10, PRINT("D7A_ERROR_NO_ACK\r\n"); break; /// RX timeout case D7A_ERROR_RX_TO: // = -11, PRINT("D7A_ERROR_RX_TO\r\n"); break; default: PRINT("Unknown Error %d\r\n", error); break; } } else if (ALP_ITF_TYPE_LWAN == itf) { PRINT("ITF[%02X] Error %d\r\n", itf, error); } else { PRINT("ITF[%02X] Error %d\r\n", itf, error); } } else { PRINT("ITF[%02X] ALP: ", itf); switch (error) { // Not really errors, more like status case ALP_ERR_ITF_FULL: // 0x02: For interfaces supporting buffering, indicates buffer reached maximum capacity (no data loss) PRINT("ALP_ERR_ITF_FULL\r\n"); break; case ALP_ERR_PARTIAL_COMPLETION: // 0x01: Action received and partially completed at response. To be completed after response PRINT("ALP_ERR_PARTIAL_COMPLETION\r\n"); break; // ALP Errors case ALP_ERR_NONE: // 0x00: Action completed (OK) PRINT("ALP_ERR_NONE\r\n"); break; case ALP_ERR_FILE_NOT_FOUND: // 0xFF: Error access file: File ID does not exist PRINT("ALP_ERR_FILE_NOT_FOUND\r\n"); break; case ALP_ERR_FILE_EXIST: // 0xFE: Error create file: File ID already exists PRINT("ALP_ERR_FILE_EXIST\r\n"); break; case ALP_ERR_FILE_NOT_RESTORABLE: // 0xFD: Error restore file: File is not restorable PRINT("ALP_ERR_FILE_NOT_RESTORABLEr\n"); break; case ALP_ERR_PERMISSION_DENIED: // 0xFC: Error access file: Insufficient permissions PRINT("ALP_ERR_PERMISSION_DENIED\r\n"); break; case ALP_ERR_LENGTH_OVERFLOW: // 0xFB: Error create file: Supplied length (in header) is beyond file limits PRINT("ALP_ERR_LENGTH_OVERFLOW\r\n"); break; case ALP_ERR_ALLOC_OVERFLOW: // 0xFA: Error create file: Supplied allocation (in header) is beyond file limits PRINT("ALP_ERR_ALLOC_OVERFLOW\r\n"); break; case ALP_ERR_OFFSET_OVERFLOW: // 0xF9: Error write: Supplied start offset is out of bounds of file allocation PRINT("ALP_ERR_OFFSET_OVERFLOW\r\n"); break; case ALP_ERR_WRITE_OVERFLOW: // 0xF8: Error complete write: Supplied data goes beyond file allocation PRINT("ALP_ERR_WRITE_OVERFLOW\r\n"); break; case ALP_ERR_WRITE_ERROR: // 0xF7: Error write: impossible to write in storage location PRINT("ALP_ERR_WRITE_ERROR\r\n"); break; case ALP_ERR_OPERATION_UNKNOWN: // 0xF6: Error unknown Operation PRINT("ALP_ERR_OPERATION_UNKNOWN\r\n"); break; case ALP_ERR_OPERAND_INCOMPLETE: // 0xF5: Error incomplete Operand PRINT("ALP_ERR_OPERAND_INCOMPLETE\r\n"); break; case ALP_ERR_OPERAND_WRONG_FORMAT: // 0xF4: Error wrong Operand format PRINT("ALP_ERR_OPERAND_WRONG_FORMAT\r\n"); break; case ALP_ERR_ITF_INVALID: // 0xF3: Error invalid interface PRINT("ALP_ERR_ITF_INVALID\r\n"); break; case ALP_ERR_ITF_OVERFLOW: // 0xF2: Error interface overflown (i.e. resources exhausted, buffer full with data discarded) PRINT("ALP_ERR_ITF_OVERFLOW\r\n"); break; case ALP_ERR_QUERY_FAIL: // 0xF1: (Group of) Query result was false (Informative error code). PRINT("ALP_ERR_QUERY_FAIL\r\n"); break; case ALP_ERR_ITF_NOT_SPECIFIED: PRINT("ALP_ERR_ITF_NOT_SPECIFIED\r\n"); break; // Other Errors case ALP_ERR_UNKNOWN: // 0x80: Unknown error PRINT("ALP_ERR_UNKNOWN\r\n"); break; case ALP_ERR_FS_TIMEOUT: // 0x81: Internal FS Error PRINT("ALP_ERR_FS_TIMEOUT\r\n"); break; case ALP_ERR_ITF_UNKNOWN: // 0x82: Unknown Interface PRINT("ALP_ERR_ITF_UNKNOWN\r\n"); break; case ALP_ERR_ITF_TIMEOUT: // 0x83: Internal ITF Error PRINT("ALP_ERR_ITF_TIMEOUT\r\n"); break; default: PRINT("Unknown Error %d\r\n", error); break; } } }