sc03mpd.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. * sc03mpd.c
  3. *
  4. * Created on: Jul 12, 2022
  5. * Author: jylew
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include "sc03mpd/sc03mpd.h"
  11. #define SC03MPD_UTL_NUSD(v) (void)(v)
  12. #define SC03MPD_UTL_V_HI(v) ((uint8_t)(((v) & 0xFF00) >> 8))
  13. #define SC03MPD_UTL_V_LO(v) ((uint8_t)(((v) & 0x00FF) >> 0))
  14. #define VC0706_PSN_REQ (0x56)
  15. #define VC0706_PSN_REP (0x76)
  16. #define SC03MPD_CMD_BDR (0x24) // SET BAUD RATE
  17. #define SC03MPD_CMD_RST (0x26) // RESET
  18. #define SC03MPD_CMD_CMP (0x31) // SET IMAGE COMPRESSION RATE
  19. #define SC03MPD_CMD_RES (0x31) // SET IMAGE RESOLUTION
  20. #define SC03MPD_CMD_CDB (0x31) // CHANGE DEFAULT BAUD RATE
  21. #define SC03MPD_CMD_IMG (0x32) // READ IMAGE DATA
  22. #define SC03MPD_CMD_LEN (0x34) // READ IMAGE DATA LENGTH
  23. #define SC03MPD_CMD_CTR (0x36) // CAPTURE IMAGE
  24. #define SC03MPD_CMD_STP (0x36) // STOP CAPTURE
  25. #define SC03MPD_CMD_CLR (0x3C) // COLOR CONTROL MODE AND SHOW MODE
  26. #define SC03MPD_PKT_REQ_LEN (4)
  27. #define SC03MPD_PKT_REP_LEN (5)
  28. #define SC03MPD_PKT_DAT_LEN (16)
  29. #define SC03MPD_PKT_MAX_MTU (SC03MPD_PKT_REP_LEN + SC03MPD_PKT_DAT_LEN)
  30. #pragma pack(push, 1)
  31. typedef struct
  32. {
  33. uint8_t psn; // Protocol Sign
  34. uint8_t dsn; // Device Serial Number
  35. uint8_t cmd; // Command
  36. uint8_t len; // Data length
  37. uint8_t dat[0];
  38. }
  39. sc03mpd_req_t;
  40. typedef struct
  41. {
  42. uint8_t psn; // Protocol Sign
  43. uint8_t dsn; // Device Serial Number
  44. uint8_t cmd; // Command
  45. uint8_t sts; // Status
  46. uint8_t len; // Data length
  47. uint8_t dat[0];
  48. }
  49. sc03mpd_rep_t;
  50. typedef union
  51. {
  52. sc03mpd_req_t req_hdr;
  53. sc03mpd_rep_t rep_hdr;
  54. uint8_t pkt_buf[SC03MPD_PKT_MAX_MTU];
  55. }
  56. sc03mpd_transaction_t;
  57. #pragma pack(pop)
  58. typedef void (*sc03mpd_cmd_builder)(sc03mpd_transaction_t*, uint16_t, uint16_t);
  59. static void sc03mpd_init_trx(sc03mpd_transaction_t* trx, uint8_t cmd, uint8_t len)
  60. {
  61. trx->req_hdr.psn = VC0706_PSN_REQ;
  62. trx->req_hdr.dsn = SC03MPD_DSN_DEF;
  63. trx->req_hdr.cmd = cmd;
  64. trx->req_hdr.len = len;
  65. }
  66. static void sc03mpd_build_rst(sc03mpd_transaction_t* trx, uint16_t arg0, uint16_t arg1)
  67. {
  68. SC03MPD_UTL_NUSD(arg0);
  69. SC03MPD_UTL_NUSD(arg1);
  70. sc03mpd_init_trx(trx, SC03MPD_CMD_RST, 0);
  71. }
  72. static void sc03mpd_build_bdr(sc03mpd_transaction_t* trx, uint16_t baud, uint16_t arg1)
  73. {
  74. SC03MPD_UTL_NUSD(arg1);
  75. sc03mpd_init_trx(trx, SC03MPD_CMD_BDR, 3);
  76. trx->req_hdr.dat[0] = 0x01;
  77. trx->req_hdr.dat[1] = SC03MPD_UTL_V_HI(baud);
  78. trx->req_hdr.dat[2] = SC03MPD_UTL_V_LO(baud);
  79. }
  80. static void sc03mpd_build_cdb(sc03mpd_transaction_t* trx, uint16_t baud, uint16_t arg1)
  81. {
  82. SC03MPD_UTL_NUSD(arg1);
  83. sc03mpd_init_trx(trx, SC03MPD_CMD_CDB, 6);
  84. trx->req_hdr.dat[0] = 0x04;
  85. trx->req_hdr.dat[1] = 0x02;
  86. trx->req_hdr.dat[2] = 0x00;
  87. trx->req_hdr.dat[3] = 0x08;
  88. trx->req_hdr.dat[4] = SC03MPD_UTL_V_HI(baud);
  89. trx->req_hdr.dat[5] = SC03MPD_UTL_V_LO(baud);
  90. }
  91. static void sc03mpd_build_cmp(sc03mpd_transaction_t* trx, uint16_t cmpr, uint16_t arg1)
  92. {
  93. SC03MPD_UTL_NUSD(arg1);
  94. sc03mpd_init_trx(trx, SC03MPD_CMD_CMP, 5);
  95. trx->req_hdr.dat[0] = 0x01;
  96. trx->req_hdr.dat[1] = 0x01;
  97. trx->req_hdr.dat[2] = 0x12;
  98. trx->req_hdr.dat[3] = 0x04;
  99. trx->req_hdr.dat[4] = (uint8_t)cmpr;
  100. }
  101. static void sc03mpd_build_res(sc03mpd_transaction_t* trx, uint16_t resn, uint16_t arg1)
  102. {
  103. SC03MPD_UTL_NUSD(arg1);
  104. sc03mpd_init_trx(trx, SC03MPD_CMD_RES, 5);
  105. trx->req_hdr.dat[0] = 0x04;
  106. trx->req_hdr.dat[1] = 0x01;
  107. trx->req_hdr.dat[2] = 0x00;
  108. trx->req_hdr.dat[3] = 0x19;
  109. trx->req_hdr.dat[4] = (uint8_t)resn;
  110. }
  111. static void sc03mpd_build_ctr(sc03mpd_transaction_t* trx, uint16_t arg0, uint16_t arg1)
  112. {
  113. SC03MPD_UTL_NUSD(arg0);
  114. SC03MPD_UTL_NUSD(arg1);
  115. sc03mpd_init_trx(trx, SC03MPD_CMD_CTR, 1);
  116. trx->req_hdr.dat[0] = 0x00;
  117. }
  118. static void sc03mpd_build_stp(sc03mpd_transaction_t* trx, uint16_t arg0, uint16_t arg1)
  119. {
  120. SC03MPD_UTL_NUSD(arg0);
  121. SC03MPD_UTL_NUSD(arg1);
  122. sc03mpd_init_trx(trx, SC03MPD_CMD_STP, 1);
  123. trx->req_hdr.dat[0] = 0x03; /* in case of two images capture, this parameter should be 0x02 */
  124. }
  125. static void sc03mpd_build_len(sc03mpd_transaction_t* trx, uint16_t arg0, uint16_t arg1)
  126. {
  127. SC03MPD_UTL_NUSD(arg0);
  128. SC03MPD_UTL_NUSD(arg1);
  129. sc03mpd_init_trx(trx, SC03MPD_CMD_LEN, 1);
  130. trx->req_hdr.dat[0] = 0x00;
  131. }
  132. static void sc03mpd_build_img(sc03mpd_transaction_t* trx, uint16_t addr, uint16_t size)
  133. {
  134. sc03mpd_init_trx(trx, SC03MPD_CMD_IMG, 12);
  135. trx->req_hdr.dat[ 0] = 0x00;
  136. trx->req_hdr.dat[ 1] = 0x0A;
  137. trx->req_hdr.dat[ 2] = 0x00;
  138. trx->req_hdr.dat[ 3] = 0x00;
  139. trx->req_hdr.dat[ 4] = SC03MPD_UTL_V_HI(addr);
  140. trx->req_hdr.dat[ 5] = SC03MPD_UTL_V_LO(addr);
  141. trx->req_hdr.dat[ 6] = 0x00;
  142. trx->req_hdr.dat[ 7] = 0x00;
  143. trx->req_hdr.dat[ 8] = SC03MPD_UTL_V_HI(size);
  144. trx->req_hdr.dat[ 9] = SC03MPD_UTL_V_LO(size);
  145. trx->req_hdr.dat[10] = 0x00;
  146. trx->req_hdr.dat[11] = 0x0A;
  147. }
  148. static void sc03mpd_build_clr(sc03mpd_transaction_t* trx, uint16_t showMode, uint16_t arg1)
  149. {
  150. SC03MPD_UTL_NUSD(arg1);
  151. sc03mpd_init_trx(trx, SC03MPD_CMD_CLR, 2);
  152. trx->req_hdr.dat[0] = 0x01;
  153. trx->req_hdr.dat[1] = (uint8_t)showMode;
  154. }
  155. static int32_t sc03mpd_do_transaction(sc03mpd_ifx_t* ifx, sc03mpd_transaction_t* trx, sc03mpd_cmd_builder builder, uint16_t arg0, uint16_t arg1)
  156. {
  157. builder(trx, arg0, arg1);
  158. uint8_t dsn = trx->req_hdr.dsn;
  159. uint8_t cmd = trx->req_hdr.cmd;
  160. uint8_t txn = sizeof(sc03mpd_req_t) + trx->req_hdr.len;
  161. uint8_t rxn = sizeof(sc03mpd_rep_t);
  162. if (ifx->sendif(ifx, trx->pkt_buf, txn) != txn)
  163. return VC0706_STS_ECOM;
  164. if (ifx->recvif(ifx, trx->pkt_buf, rxn) != rxn)
  165. return VC0706_STS_ECOM;
  166. if (trx->rep_hdr.dsn != dsn) return VC0706_STS_ECOM;
  167. if (trx->rep_hdr.cmd != cmd) return VC0706_STS_ECOM;
  168. if (trx->rep_hdr.psn != VC0706_PSN_REP ) return VC0706_STS_ECOM;
  169. if (trx->rep_hdr.sts != VC0706_STS_ENON) return -((int32_t)trx->rep_hdr.sts);
  170. uint8_t rxd = trx->rep_hdr.len;
  171. if (rxd > 0)
  172. {
  173. if (ifx->recvif(ifx, &trx->pkt_buf[rxn], rxd) != rxd)
  174. return VC0706_STS_ECOM;
  175. }
  176. return VC0706_STS_ENON;
  177. }
  178. static int32_t sc03mpd_validate_baud(uint16_t baud)
  179. {
  180. switch (baud)
  181. {
  182. case SC03MPD_BDR_9600 :
  183. case SC03MPD_BDR_19200 :
  184. case SC03MPD_BDR_38400 :
  185. case SC03MPD_BDR_56700 :
  186. case SC03MPD_BDR_115200: return 0;
  187. }
  188. return 1;
  189. }
  190. static int32_t sc03mpd_validate_ires(uint8_t ires)
  191. {
  192. switch (ires)
  193. {
  194. case SC03MPD_RES_640_480:
  195. case SC03MPD_RES_320_240:
  196. case SC03MPD_RES_160_120: return 0;
  197. }
  198. return 1;
  199. }
  200. static int32_t sc03mpd_validate_clr(uint8_t clr)
  201. {
  202. switch (clr)
  203. {
  204. case SC03MPD_CLR_AUTO:
  205. case SC03MPD_CLR_COLOR:
  206. case SC03MPD_CLR_BW: return 0;
  207. }
  208. return 1;
  209. }
  210. int32_t sc03mpd_reset(sc03mpd_ifx_t* ifx)
  211. {
  212. sc03mpd_transaction_t trx;
  213. if (sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_rst, 0, 0))
  214. return VC0706_STS_ECOM;
  215. // Some ASCII string follows after vc0706 response.
  216. uint8_t dbuf[192] = { 0, };
  217. int32_t nrxd = 0;
  218. int32_t accq = 0;
  219. int32_t rest = sizeof(dbuf) - 1;
  220. while (rest > 0)
  221. {
  222. if ((nrxd = ifx->recvif(ifx, &dbuf[accq], rest)) <= 0)
  223. break;
  224. accq += nrxd;
  225. rest -= nrxd;
  226. }
  227. #ifdef SHOW_RESET_RESULT
  228. printf("%s\n", dbuf);
  229. #endif
  230. return VC0706_STS_ENON;
  231. }
  232. int32_t sc03mpd_set_baud(sc03mpd_ifx_t* ifx, uint16_t baud, uint8_t save)
  233. {
  234. if (sc03mpd_validate_baud(baud))
  235. return VC0706_STS_EFMT;
  236. sc03mpd_transaction_t trx;
  237. sc03mpd_cmd_builder builder = (save)? sc03mpd_build_cdb : sc03mpd_build_bdr;
  238. return sc03mpd_do_transaction(ifx, &trx, builder, baud, 0);
  239. }
  240. int32_t sc03mpd_set_icmp(sc03mpd_ifx_t* ifx, uint8_t cmpr)
  241. {
  242. sc03mpd_transaction_t trx;
  243. return sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_cmp, cmpr, 0);
  244. }
  245. int32_t sc03mpd_set_ires(sc03mpd_ifx_t* ifx, uint8_t ires)
  246. {
  247. if (sc03mpd_validate_ires(ires))
  248. return VC0706_STS_EFMT;
  249. sc03mpd_transaction_t trx;
  250. return sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_res, ires, 0);
  251. }
  252. int32_t sc03mpd_get_ilen(sc03mpd_ifx_t* ifx, uint16_t* length)
  253. {
  254. sc03mpd_transaction_t trx;
  255. if (sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_len, 0, 0))
  256. return VC0706_STS_ECOM;
  257. *length = ((uint16_t)trx.rep_hdr.dat[2] << 8) |
  258. ((uint16_t)trx.req_hdr.dat[3] << 0);
  259. return VC0706_STS_ENON;
  260. }
  261. int32_t sc03mpd_get_idat(sc03mpd_ifx_t* ifx, uint16_t addr, uint16_t size, uint8_t* dbuf)
  262. {
  263. if (dbuf == NULL) return VC0706_STS_EINT;
  264. if (size == 0 ) return VC0706_STS_EINT;
  265. sc03mpd_transaction_t trx;
  266. if (sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_img, addr, size))
  267. return VC0706_STS_ECOM;
  268. int32_t nrxd = 0;
  269. int32_t accq = 0;
  270. int32_t rest = size;
  271. while (rest > 0)
  272. {
  273. if ((nrxd = ifx->recvif(ifx, &dbuf[accq], rest)) <= 0)
  274. return VC0706_STS_ECOM;
  275. accq += nrxd;
  276. rest -= nrxd;
  277. }
  278. sc03mpd_rep_t res;
  279. if (ifx->recvif(ifx, (uint8_t*)&res, sizeof(res)) != sizeof(res))
  280. return VC0706_STS_ECOM;
  281. if (res.psn != trx.rep_hdr.psn) return VC0706_STS_ECOM;
  282. if (res.dsn != trx.rep_hdr.dsn) return VC0706_STS_ECOM;
  283. if (res.cmd != trx.rep_hdr.cmd) return VC0706_STS_ECOM;
  284. if (res.sts != trx.rep_hdr.sts) return VC0706_STS_ECOM;
  285. if (res.len != trx.rep_hdr.len) return VC0706_STS_ECOM;
  286. return VC0706_STS_ENON;
  287. }
  288. int32_t sc03mpd_capture(sc03mpd_ifx_t* ifx)
  289. {
  290. sc03mpd_transaction_t trx;
  291. return sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_ctr, 0, 0);
  292. }
  293. int32_t sc03mpd_stop(sc03mpd_ifx_t* ifx)
  294. {
  295. sc03mpd_transaction_t trx;
  296. return sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_stp, 0, 0);
  297. }
  298. int32_t sc03mpd_set_clr(sc03mpd_ifx_t* ifx, uint8_t showMode)
  299. {
  300. if (sc03mpd_validate_clr(showMode))
  301. return VC0706_STS_EFMT;
  302. sc03mpd_transaction_t trx;
  303. return sc03mpd_do_transaction(ifx, &trx, sc03mpd_build_clr, showMode, 0);
  304. }