platform.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. #include "platform.h"
  2. #include "isup_sdk.h"
  3. #include <pthread.h>
  4. #include <sys/socket.h>
  5. #include <netinet/in.h>
  6. #include <arpa/inet.h>
  7. /* ============================================================
  8. * 内部数据结构
  9. * ============================================================ */
  10. /* 已注册设备信息 */
  11. typedef struct {
  12. char device_id[MAX_DEVICE_ID];
  13. int user_id;
  14. time_t register_time;
  15. time_t last_heartbeat;
  16. int is_online;
  17. DevRegInfo info;
  18. pthread_mutex_t lock;
  19. } RegisteredDevice;
  20. /* 全局变量 */
  21. static int g_cms_initialized = 0;
  22. static int g_cms_listen_socket = -1;
  23. static pthread_t g_cms_listen_thread;
  24. static int g_cms_stop = 0;
  25. static DEVICE_REGISTER_CB g_reg_callback = NULL;
  26. static void* g_reg_user_data = NULL;
  27. static DeviceStatusCB g_status_callback = NULL;
  28. static void* g_status_user_data = NULL;
  29. static RegisteredDevice g_devices[256];
  30. static int g_device_count = 0;
  31. static int g_user_id_counter = 0;
  32. /* ============================================================
  33. * HCNetSDK ISUP接口声明(外部动态库)
  34. * ============================================================
  35. * 实际编译时需要链接HCNetSDK库:
  36. * - libhcnetsdk.so (Linux)
  37. * - 头文件: HCNetSDK.h
  38. *
  39. * 以下为ISUP SDK的核心接口声明:
  40. * ============================================================ */
  41. /* 模拟实现(无实际SDK时的测试用) */
  42. #ifndef HAVE_HCNETSDK
  43. /* 如果没有实际SDK,使用模拟实现 */
  44. int NET_ECMS_Init(void) {
  45. LOG_INFO("[Mock] NET_ECMS_Init called");
  46. return SUCCESS;
  47. }
  48. void NET_ECMS_Clean(void) {
  49. LOG_INFO("[Mock] NET_ECMS_Clean called");
  50. }
  51. int NET_ECMS_StartListen(char* pszListenIP, short sListenPort, void* pUser) {
  52. (void)pUser;
  53. LOG_INFO("[Mock] NET_ECMS_StartListen: IP=%s, Port=%d", pszListenIP, sListenPort);
  54. return SUCCESS;
  55. }
  56. void NET_ECMS_StopListen(void) {
  57. LOG_INFO("[Mock] NET_ECMS_StopListen called");
  58. }
  59. int NET_ECMS_Login(char* pszDVRIP, short sDVRPort, char* szUserName, char* szPassword, void* pUser) {
  60. (void)pszDVRIP;
  61. (void)szUserName;
  62. (void)szPassword;
  63. (void)pUser;
  64. LOG_INFO("[Mock] NET_ECMS_Login: IP=%s, Port=%d", pszDVRIP, sDVRPort);
  65. return ++g_user_id_counter; /* 模拟返回用户ID */
  66. }
  67. int NET_ECMS_Logout(int iUserID) {
  68. LOG_INFO("[Mock] NET_ECMS_Logout: UserID=%d", iUserID);
  69. return SUCCESS;
  70. }
  71. int NET_ECMS_SetAutoReconnect(int iUserID, int bAutoReconnect, int iInterval) {
  72. LOG_INFO("[Mock] NET_ECMS_SetAutoReconnect: UserID=%d, Enable=%d, Interval=%d",
  73. iUserID, bAutoReconnect, iInterval);
  74. return SUCCESS;
  75. }
  76. int NET_ECMS_SendHeartBeat(int iUserID) {
  77. LOG_INFO("[Mock] NET_ECMS_SendHeartBeat: UserID=%d", iUserID);
  78. return SUCCESS;
  79. }
  80. int NET_ESTREAM_Init(void) {
  81. LOG_INFO("[Mock] NET_ESTREAM_Init called");
  82. return SUCCESS;
  83. }
  84. void NET_ESTREAM_Clean(void) {
  85. LOG_INFO("[Mock] NET_ESTREAM_Clean called");
  86. }
  87. int NET_ESTREAM_StartListenPlayBack(char* pszListenIP, short sListenPort, void* pCallback, void* pUser) {
  88. (void)pCallback;
  89. (void)pUser;
  90. LOG_INFO("[Mock] NET_ESTREAM_StartListenPlayBack: IP=%s, Port=%d", pszListenIP, sListenPort);
  91. return SUCCESS;
  92. }
  93. void NET_ESTREAM_StopListenPlayBack(void) {
  94. LOG_INFO("[Mock] NET_ESTREAM_StopListenPlayBack called");
  95. }
  96. int NET_ESTREAM_SetPlayBackDataCB(int iStreamHandle, void* pCallback, void* pUser) {
  97. (void)pCallback;
  98. (void)pUser;
  99. LOG_INFO("[Mock] NET_ESTREAM_SetPlayBackDataCB: Handle=%d", iStreamHandle);
  100. return SUCCESS;
  101. }
  102. int NET_ECMS_StartPlayBack(int iUserID, char* pszDevIP, short sDevPort, char* pszPlayBackIP, short sPlayBackPort, int iChannel) {
  103. (void)pszDevIP;
  104. (void)sDevPort;
  105. (void)pszPlayBackIP;
  106. (void)sPlayBackPort;
  107. LOG_INFO("[Mock] NET_ECMS_StartPlayBack: UserID=%d, Channel=%d", iUserID, iChannel);
  108. return SUCCESS;
  109. }
  110. int NET_ECMS_StopPlayBack(int iUserID) {
  111. LOG_INFO("[Mock] NET_ECMS_StopPlayBack: UserID=%d", iUserID);
  112. return SUCCESS;
  113. }
  114. int NET_EALARM_Init(void) {
  115. LOG_INFO("[Mock] NET_EALARM_Init called");
  116. return SUCCESS;
  117. }
  118. void NET_EALARM_Clean(void) {
  119. LOG_INFO("[Mock] NET_EALARM_Clean called");
  120. }
  121. int NET_EALARM_StartListen(char* pszListenIP, short sListenPort, void* pAlarmCallback, void* pUser) {
  122. (void)pAlarmCallback;
  123. (void)pUser;
  124. LOG_INFO("[Mock] NET_EALARM_StartListen: IP=%s, Port=%d", pszListenIP, sListenPort);
  125. return SUCCESS;
  126. }
  127. void NET_EALARM_StopListen(void) {
  128. LOG_INFO("[Mock] NET_EALARM_StopListen called");
  129. }
  130. #endif /* HAVE_HCNETSDK */
  131. /* ============================================================
  132. * 内部函数
  133. * ============================================================ */
  134. static RegisteredDevice* find_device(const char* device_id) {
  135. for (int i = 0; i < g_device_count; i++) {
  136. if (strcmp(g_devices[i].device_id, device_id) == 0) {
  137. return &g_devices[i];
  138. }
  139. }
  140. return NULL;
  141. }
  142. static int add_device(const char* device_id, int user_id) {
  143. if (g_device_count >= 256) {
  144. LOG_ERROR("Maximum device count reached");
  145. return FAILURE;
  146. }
  147. RegisteredDevice* dev = &g_devices[g_device_count];
  148. safe_strcpy(dev->device_id, device_id, MAX_DEVICE_ID);
  149. dev->user_id = user_id;
  150. dev->register_time = time(NULL);
  151. dev->last_heartbeat = time(NULL);
  152. dev->is_online = 1;
  153. pthread_mutex_init(&dev->lock, NULL);
  154. g_device_count++;
  155. LOG_INFO("Device registered: %s (UserID=%d, Total=%d)", device_id, user_id, g_device_count);
  156. return SUCCESS;
  157. }
  158. static void remove_device(const char* device_id) {
  159. for (int i = 0; i < g_device_count; i++) {
  160. if (strcmp(g_devices[i].device_id, device_id) == 0) {
  161. pthread_mutex_destroy(&g_devices[i].lock);
  162. g_device_count--;
  163. /* 移动最后一个元素到删除位置 */
  164. if (i < g_device_count) {
  165. memcpy(&g_devices[i], &g_devices[g_device_count], sizeof(RegisteredDevice));
  166. }
  167. LOG_INFO("Device removed: %s (Total=%d)", device_id, g_device_count);
  168. return;
  169. }
  170. }
  171. }
  172. /* CMS监听线程函数 */
  173. static void* cms_listen_thread_func(void* arg) {
  174. (void)arg;
  175. LOG_INFO("CMS listen thread started");
  176. while (!g_cms_stop) {
  177. /* 在实际实现中,这里会阻塞等待设备注册请求 */
  178. /* 模拟实现中,我们只是休眠并检查停止标志 */
  179. sleep_milliseconds(1000);
  180. /* 检查心跳超时 */
  181. time_t now = time(NULL);
  182. for (int i = 0; i < g_device_count; i++) {
  183. if (g_devices[i].is_online && (now - g_devices[i].last_heartbeat > 90)) {
  184. LOG_WARN("Device heartbeat timeout: %s", g_devices[i].device_id);
  185. g_devices[i].is_online = 0;
  186. if (g_status_callback) {
  187. g_status_callback(g_devices[i].device_id, DEVICE_STATUS_OFFLINE, g_status_user_data);
  188. }
  189. }
  190. }
  191. }
  192. LOG_INFO("CMS listen thread stopped");
  193. return NULL;
  194. }
  195. /* ============================================================
  196. * 公共接口实现
  197. * ============================================================ */
  198. int platform_cms_init(void) {
  199. if (g_cms_initialized) {
  200. LOG_WARN("CMS already initialized");
  201. return SUCCESS;
  202. }
  203. LOG_INFO("Initializing CMS library...");
  204. /* 调用HCNetSDK初始化 */
  205. if (NET_ECMS_Init() != SUCCESS) {
  206. LOG_ERROR("Failed to initialize CMS library");
  207. return FAILURE;
  208. }
  209. /* 初始化报警库 */
  210. if (NET_EALARM_Init() != SUCCESS) {
  211. LOG_WARN("Failed to initialize ALARM library (non-fatal)");
  212. }
  213. g_cms_initialized = 1;
  214. LOG_INFO("CMS library initialized successfully");
  215. return SUCCESS;
  216. }
  217. void platform_cms_cleanup(void) {
  218. if (!g_cms_initialized) return;
  219. LOG_INFO("Cleaning up CMS library...");
  220. g_cms_stop = 1;
  221. if (g_cms_listen_socket >= 0) {
  222. close(g_cms_listen_socket);
  223. g_cms_listen_socket = -1;
  224. }
  225. if (g_cms_listen_thread != 0) {
  226. pthread_join(g_cms_listen_thread, NULL);
  227. g_cms_listen_thread = 0;
  228. }
  229. /* 清理所有设备 */
  230. for (int i = 0; i < g_device_count; i++) {
  231. pthread_mutex_destroy(&g_devices[i].lock);
  232. }
  233. g_device_count = 0;
  234. /* 调用HCNetSDK清理 */
  235. NET_ECMS_Clean();
  236. NET_EALARM_Clean();
  237. g_cms_initialized = 0;
  238. LOG_INFO("CMS library cleaned up");
  239. }
  240. int platform_cms_start_listen(const char* listen_ip, short listen_port,
  241. DEVICE_REGISTER_CB reg_callback, void* user_data) {
  242. if (listen_ip == NULL || reg_callback == NULL) {
  243. LOG_ERROR("Invalid parameters");
  244. return FAILURE;
  245. }
  246. g_reg_callback = reg_callback;
  247. g_reg_user_data = user_data;
  248. LOG_INFO("Starting CMS listen on %s:%d...", listen_ip, listen_port);
  249. /* 调用HCNetSDK启动监听 */
  250. if (NET_ECMS_StartListen((char*)listen_ip, listen_port, NULL) != SUCCESS) {
  251. LOG_ERROR("Failed to start CMS listen");
  252. return FAILURE;
  253. }
  254. /* 启动监听线程 */
  255. g_cms_stop = 0;
  256. if (pthread_create(&g_cms_listen_thread, NULL, cms_listen_thread_func, NULL) != 0) {
  257. LOG_ERROR("Failed to create CMS listen thread");
  258. return FAILURE;
  259. }
  260. LOG_INFO("CMS listen started successfully");
  261. return SUCCESS;
  262. }
  263. void platform_cms_stop_listen(void) {
  264. LOG_INFO("Stopping CMS listen...");
  265. g_cms_stop = 1;
  266. if (g_cms_listen_socket >= 0) {
  267. close(g_cms_listen_socket);
  268. g_cms_listen_socket = -1;
  269. }
  270. LOG_INFO("CMS listen stopped");
  271. }
  272. int platform_device_register(const char* server_ip, short server_port,
  273. const char* device_id, const char* protocol_version,
  274. const char* encrypt_key, void* user_data) {
  275. (void)protocol_version;
  276. if (server_ip == NULL || device_id == NULL) {
  277. LOG_ERROR("Invalid parameters");
  278. return FAILURE;
  279. }
  280. LOG_INFO("Registering device: %s to CMS %s:%d", device_id, server_ip, server_port);
  281. /* 检查是否已注册 */
  282. if (find_device(device_id) != NULL) {
  283. LOG_WARN("Device already registered: %s", device_id);
  284. return FAILURE;
  285. }
  286. /* 调用HCNetSDK登录 */
  287. int user_id = NET_ECMS_Login((char*)server_ip, server_port,
  288. (char*)device_id, (char*)encrypt_key, user_data);
  289. if (user_id < 0) {
  290. LOG_ERROR("Device registration failed: %s", device_id);
  291. return FAILURE;
  292. }
  293. /* 记录设备信息 */
  294. add_device(device_id, user_id);
  295. /* 设置自动重连 */
  296. NET_ECMS_SetAutoReconnect(user_id, 1, REG_RETRY_INTERVAL);
  297. /* 触发注册回调 */
  298. if (g_reg_callback) {
  299. g_reg_callback(user_id, DEV_REG_TYPE_ON, NULL, 0, NULL, 0, user_data);
  300. }
  301. /* 触发状态回调 */
  302. if (g_status_callback) {
  303. g_status_callback(device_id, DEVICE_STATUS_ONLINE, g_status_user_data);
  304. }
  305. LOG_INFO("Device registered successfully: %s (UserID=%d)", device_id, user_id);
  306. return user_id;
  307. }
  308. int platform_device_logout(int user_id) {
  309. if (user_id < 0) {
  310. LOG_ERROR("Invalid user ID");
  311. return FAILURE;
  312. }
  313. LOG_INFO("Logging out device: UserID=%d", user_id);
  314. /* 查找设备 */
  315. for (int i = 0; i < g_device_count; i++) {
  316. if (g_devices[i].user_id == user_id) {
  317. /* 触发下线回调 */
  318. if (g_reg_callback) {
  319. g_reg_callback(user_id, DEV_REG_TYPE_OFF, NULL, 0, NULL, 0, g_reg_user_data);
  320. }
  321. if (g_status_callback) {
  322. g_status_callback(g_devices[i].device_id, DEVICE_STATUS_OFFLINE, g_status_user_data);
  323. }
  324. remove_device(g_devices[i].device_id);
  325. break;
  326. }
  327. }
  328. /* 调用HCNetSDK登出 */
  329. NET_ECMS_Logout(user_id);
  330. LOG_INFO("Device logged out: UserID=%d", user_id);
  331. return SUCCESS;
  332. }
  333. int platform_set_auto_reconnect(int user_id, int enable, int interval) {
  334. return NET_ECMS_SetAutoReconnect(user_id, enable, interval);
  335. }
  336. int platform_send_heartbeat(int user_id) {
  337. return NET_ECMS_SendHeartBeat(user_id);
  338. }
  339. void platform_register_status_callback(DeviceStatusCB cb, void* user_data) {
  340. g_status_callback = cb;
  341. g_status_user_data = user_data;
  342. }
  343. int platform_get_device_info(const char* device_id, DevRegInfo* info) {
  344. if (device_id == NULL || info == NULL) {
  345. return FAILURE;
  346. }
  347. RegisteredDevice* dev = find_device(device_id);
  348. if (dev == NULL) {
  349. return NOT_FOUND;
  350. }
  351. memcpy(info, &dev->info, sizeof(DevRegInfo));
  352. return SUCCESS;
  353. }
  354. int platform_get_online_devices(char devices[][MAX_DEVICE_ID], int max_devices) {
  355. int count = 0;
  356. for (int i = 0; i < g_device_count && count < max_devices; i++) {
  357. if (g_devices[i].is_online) {
  358. safe_strcpy(devices[count], g_devices[i].device_id, MAX_DEVICE_ID);
  359. count++;
  360. }
  361. }
  362. return count;
  363. }