/* * sc03mpd.c * * Created on: Jul 12, 2022 * Author: jylew */ #include #include #include #include "sc03mpd/sc03mpd.h" #define SC03MPD_UTL_NUSD(v) (void)(v) #define SC03MPD_UTL_V_HI(v) ((uint8_t)(((v) & 0xFF00) >> 8)) #define SC03MPD_UTL_V_LO(v) ((uint8_t)(((v) & 0x00FF) >> 0)) #define VC0706_PSN_REQ (0x56) #define VC0706_PSN_REP (0x76) #define SC03MPD_CMD_BDR (0x24) // SET BAUD RATE #define SC03MPD_CMD_RST (0x26) // RESET #define SC03MPD_CMD_CMP (0x31) // SET IMAGE COMPRESSION RATE #define SC03MPD_CMD_RES (0x31) // SET IMAGE RESOLUTION #define SC03MPD_CMD_CDB (0x31) // CHANGE DEFAULT BAUD RATE #define SC03MPD_CMD_IMG (0x32) // READ IMAGE DATA #define SC03MPD_CMD_LEN (0x34) // READ IMAGE DATA LENGTH #define SC03MPD_CMD_CTR (0x36) // CAPTURE IMAGE #define SC03MPD_CMD_STP (0x36) // STOP CAPTURE #define SC03MPD_CMD_CLR (0x3C) // COLOR CONTROL MODE AND SHOW MODE #define SC03MPD_PKT_REQ_LEN (4) #define SC03MPD_PKT_REP_LEN (5) #define SC03MPD_PKT_DAT_LEN (16) #define SC03MPD_PKT_MAX_MTU (SC03MPD_PKT_REP_LEN + SC03MPD_PKT_DAT_LEN) #pragma pack(push, 1) typedef struct { uint8_t psn; // Protocol Sign uint8_t dsn; // Device Serial Number uint8_t cmd; // Command uint8_t len; // Data length uint8_t dat[0]; } sc03mpd_req_t; typedef struct { uint8_t psn; // Protocol Sign uint8_t dsn; // Device Serial Number uint8_t cmd; // Command uint8_t sts; // Status uint8_t len; // Data length uint8_t dat[0]; } sc03mpd_rep_t; typedef union { sc03mpd_req_t req_hdr; sc03mpd_rep_t rep_hdr; uint8_t pkt_buf[SC03MPD_PKT_MAX_MTU]; } sc03mpd_transaction_t; #pragma pack(pop) typedef void (*sc03mpd_cmd_builder)(sc03mpd_transaction_t*, uint16_t, uint16_t); static void sc03mpd_init_trx(sc03mpd_transaction_t* trx, uint8_t cmd, uint8_t len) { trx->req_hdr.psn = VC0706_PSN_REQ; trx->req_hdr.dsn = SC03MPD_DSN_DEF; trx->req_hdr.cmd = cmd; trx->req_hdr.len = len; } static void sc03mpd_build_rst(sc03mpd_transaction_t* trx, uint16_t arg0, uint16_t arg1) { SC03MPD_UTL_NUSD(arg0); SC03MPD_UTL_NUSD(arg1); sc03mpd_init_trx(trx, SC03MPD_CMD_RST, 0); } static void sc03mpd_build_bdr(sc03mpd_transaction_t* trx, uint16_t baud, uint16_t arg1) { SC03MPD_UTL_NUSD(arg1); sc03mpd_init_trx(trx, SC03MPD_CMD_BDR, 3); trx->req_hdr.dat[0] = 0x01; trx->req_hdr.dat[1] = SC03MPD_UTL_V_HI(baud); trx->req_hdr.dat[2] = SC03MPD_UTL_V_LO(baud); } static void sc03mpd_build_cdb(sc03mpd_transaction_t* trx, uint16_t baud, uint16_t arg1) { SC03MPD_UTL_NUSD(arg1); sc03mpd_init_trx(trx, SC03MPD_CMD_CDB, 6); trx->req_hdr.dat[0] = 0x04; trx->req_hdr.dat[1] = 0x02; trx->req_hdr.dat[2] = 0x00; trx->req_hdr.dat[3] = 0x08; trx->req_hdr.dat[4] = SC03MPD_UTL_V_HI(baud); trx->req_hdr.dat[5] = SC03MPD_UTL_V_LO(baud); } static void sc03mpd_build_cmp(sc03mpd_transaction_t* trx, uint16_t cmpr, uint16_t arg1) { SC03MPD_UTL_NUSD(arg1); sc03mpd_init_trx(trx, SC03MPD_CMD_CMP, 5); trx->req_hdr.dat[0] = 0x01; trx->req_hdr.dat[1] = 0x01; trx->req_hdr.dat[2] = 0x12; trx->req_hdr.dat[3] = 0x04; trx->req_hdr.dat[4] = (uint8_t)cmpr; } static void sc03mpd_build_res(sc03mpd_transaction_t* trx, uint16_t resn, uint16_t arg1) { SC03MPD_UTL_NUSD(arg1); sc03mpd_init_trx(trx, SC03MPD_CMD_RES, 5); trx->req_hdr.dat[0] = 0x04; trx->req_hdr.dat[1] = 0x01; trx->req_hdr.dat[2] = 0x00; trx->req_hdr.dat[3] = 0x19; trx->req_hdr.dat[4] = (uint8_t)resn; } static void sc03mpd_build_ctr(sc03mpd_transaction_t* trx, uint16_t arg0, uint16_t arg1) { SC03MPD_UTL_NUSD(arg0); SC03MPD_UTL_NUSD(arg1); sc03mpd_init_trx(trx, SC03MPD_CMD_CTR, 1); trx->req_hdr.dat[0] = 0x00; } static void sc03mpd_build_stp(sc03mpd_transaction_t* trx, uint16_t arg0, uint16_t arg1) { SC03MPD_UTL_NUSD(arg0); SC03MPD_UTL_NUSD(arg1); sc03mpd_init_trx(trx, SC03MPD_CMD_STP, 1); trx->req_hdr.dat[0] = 0x03; /* in case of two images capture, this parameter should be 0x02 */ } static void sc03mpd_build_len(sc03mpd_transaction_t* trx, uint16_t arg0, uint16_t arg1) { SC03MPD_UTL_NUSD(arg0); SC03MPD_UTL_NUSD(arg1); sc03mpd_init_trx(trx, SC03MPD_CMD_LEN, 1); trx->req_hdr.dat[0] = 0x00; } static void sc03mpd_build_img(sc03mpd_transaction_t* trx, uint16_t addr, uint16_t size) { sc03mpd_init_trx(trx, SC03MPD_CMD_IMG, 12); trx->req_hdr.dat[ 0] = 0x00; trx->req_hdr.dat[ 1] = 0x0A; trx->req_hdr.dat[ 2] = 0x00; trx->req_hdr.dat[ 3] = 0x00; trx->req_hdr.dat[ 4] = SC03MPD_UTL_V_HI(addr); trx->req_hdr.dat[ 5] = SC03MPD_UTL_V_LO(addr); trx->req_hdr.dat[ 6] = 0x00; trx->req_hdr.dat[ 7] = 0x00; trx->req_hdr.dat[ 8] = SC03MPD_UTL_V_HI(size); trx->req_hdr.dat[ 9] = SC03MPD_UTL_V_LO(size); trx->req_hdr.dat[10] = 0x00; trx->req_hdr.dat[11] = 0x0A; } static void sc03mpd_build_clr(sc03mpd_transaction_t* trx, uint16_t showMode, uint16_t arg1) { SC03MPD_UTL_NUSD(arg1); sc03mpd_init_trx(trx, SC03MPD_CMD_CLR, 2); trx->req_hdr.dat[0] = 0x01; trx->req_hdr.dat[1] = (uint8_t)showMode; } static int32_t sc03mpd_do_transaction(sc03mpd_ifx_t* ifx, sc03mpd_transaction_t* trx, sc03mpd_cmd_builder builder, uint16_t arg0, uint16_t arg1) { builder(trx, arg0, arg1); uint8_t dsn = trx->req_hdr.dsn; uint8_t cmd = trx->req_hdr.cmd; uint8_t txn = sizeof(sc03mpd_req_t) + trx->req_hdr.len; uint8_t rxn = sizeof(sc03mpd_rep_t); if (ifx->sendif(ifx, trx->pkt_buf, txn) != txn) return VC0706_STS_ECOM; if (ifx->recvif(ifx, trx->pkt_buf, rxn) != rxn) return VC0706_STS_ECOM; if (trx->rep_hdr.dsn != dsn) return VC0706_STS_ECOM; if (trx->rep_hdr.cmd != cmd) return VC0706_STS_ECOM; if (trx->rep_hdr.psn != VC0706_PSN_REP ) return VC0706_STS_ECOM; if (trx->rep_hdr.sts != VC0706_STS_ENON) return -((int32_t)trx->rep_hdr.sts); uint8_t rxd = trx->rep_hdr.len; if (rxd > 0) { if (ifx->recvif(ifx, &trx->pkt_buf[rxn], rxd) != rxd) return VC0706_STS_ECOM; } return VC0706_STS_ENON; } static int32_t sc03mpd_validate_baud(uint16_t baud) { switch (baud) { case SC03MPD_BDR_9600 : case SC03MPD_BDR_19200 : case SC03MPD_BDR_38400 : case SC03MPD_BDR_56700 : case SC03MPD_BDR_115200: return 0; } return 1; } static int32_t sc03mpd_validate_ires(uint8_t ires) { switch (ires) { case SC03MPD_RES_640_480: case SC03MPD_RES_320_240: case SC03MPD_RES_160_120: return 0; } return 1; } static int32_t sc03mpd_validate_clr(uint8_t clr) { switch (clr) { case SC03MPD_CLR_AUTO: case SC03MPD_CLR_COLOR: case SC03MPD_CLR_BW: return 0; } return 1; } int32_t sc03mpd_reset(sc03mpd_ifx_t* ifx) { sc03mpd_transaction_t trx; if (sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_rst, 0, 0)) return VC0706_STS_ECOM; // Some ASCII string follows after vc0706 response. uint8_t dbuf[192] = { 0, }; int32_t nrxd = 0; int32_t accq = 0; int32_t rest = sizeof(dbuf) - 1; while (rest > 0) { if ((nrxd = ifx->recvif(ifx, &dbuf[accq], rest)) <= 0) break; accq += nrxd; rest -= nrxd; } #ifdef SHOW_RESET_RESULT printf("%s\n", dbuf); #endif return VC0706_STS_ENON; } int32_t sc03mpd_set_baud(sc03mpd_ifx_t* ifx, uint16_t baud, uint8_t save) { if (sc03mpd_validate_baud(baud)) return VC0706_STS_EFMT; sc03mpd_transaction_t trx; sc03mpd_cmd_builder builder = (save)? sc03mpd_build_cdb : sc03mpd_build_bdr; return sc03mpd_do_transaction(ifx, &trx, builder, baud, 0); } int32_t sc03mpd_set_icmp(sc03mpd_ifx_t* ifx, uint8_t cmpr) { sc03mpd_transaction_t trx; return sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_cmp, cmpr, 0); } int32_t sc03mpd_set_ires(sc03mpd_ifx_t* ifx, uint8_t ires) { if (sc03mpd_validate_ires(ires)) return VC0706_STS_EFMT; sc03mpd_transaction_t trx; return sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_res, ires, 0); } int32_t sc03mpd_get_ilen(sc03mpd_ifx_t* ifx, uint16_t* length) { sc03mpd_transaction_t trx; if (sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_len, 0, 0)) return VC0706_STS_ECOM; *length = ((uint16_t)trx.rep_hdr.dat[2] << 8) | ((uint16_t)trx.req_hdr.dat[3] << 0); return VC0706_STS_ENON; } int32_t sc03mpd_get_idat(sc03mpd_ifx_t* ifx, uint16_t addr, uint16_t size, uint8_t* dbuf) { if (dbuf == NULL) return VC0706_STS_EINT; if (size == 0 ) return VC0706_STS_EINT; sc03mpd_transaction_t trx; if (sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_img, addr, size)) return VC0706_STS_ECOM; int32_t nrxd = 0; int32_t accq = 0; int32_t rest = size; while (rest > 0) { if ((nrxd = ifx->recvif(ifx, &dbuf[accq], rest)) <= 0) return VC0706_STS_ECOM; accq += nrxd; rest -= nrxd; } sc03mpd_rep_t res; if (ifx->recvif(ifx, (uint8_t*)&res, sizeof(res)) != sizeof(res)) return VC0706_STS_ECOM; if (res.psn != trx.rep_hdr.psn) return VC0706_STS_ECOM; if (res.dsn != trx.rep_hdr.dsn) return VC0706_STS_ECOM; if (res.cmd != trx.rep_hdr.cmd) return VC0706_STS_ECOM; if (res.sts != trx.rep_hdr.sts) return VC0706_STS_ECOM; if (res.len != trx.rep_hdr.len) return VC0706_STS_ECOM; return VC0706_STS_ENON; } int32_t sc03mpd_capture(sc03mpd_ifx_t* ifx) { sc03mpd_transaction_t trx; return sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_ctr, 0, 0); } int32_t sc03mpd_stop(sc03mpd_ifx_t* ifx) { sc03mpd_transaction_t trx; return sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_stp, 0, 0); } int32_t sc03mpd_set_clr(sc03mpd_ifx_t* ifx, uint8_t showMode) { if (sc03mpd_validate_clr(showMode)) return VC0706_STS_EFMT; sc03mpd_transaction_t trx; return sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_clr, showMode, 0); }