void ICACHE_FLASH_ATTR publishAllTemperatures(void) { struct Temperature *t; int idx; if (mqttIsConnected()) { char *topic = (char*) os_malloc(100), *data = (char*) os_malloc(100); if (topic == NULL || data == NULL) { ERRORP("malloc err %s/%s\n", topic, data); startFlash(-1, 50, 50); // fast return; } for (idx = 0; idx < MAX_TEMPERATURE_SENSOR; idx++) { if (getUnmappedTemperature(idx, &t)) { os_sprintf(topic, (const char*) "/Raw/%s/%s/info", sysCfg.device_id, t->address); os_sprintf(data, (const char*) "{ \"Type\":\"Temp\", \"Value\":\"%c%d.%02d\"}", t->sign, t->val, t->fract); if (!MQTT_Publish(mqttClient, topic, data, os_strlen(data), 0, 0)) printMQTTstate(); INFOP("%s=>%s\n", topic, data); } } checkMinHeap(); os_free(topic); os_free(data); } }
obj_ptr global_env(void) { static obj_ptr _global = 0; if (!_global) { obj_ptr o; _global = CONS(obj_alloc_map(), NIL); gc_protect(_global); _env_add_primitive(_global, "+", _add); _env_add_primitive(_global, "*", _mul); _env_add_primitive(_global, "-", _sub); _env_add_primitive(_global, "/", _div); _env_add_primitive1(_global, "floor", _floor); _env_add_primitive1(_global, "++", _increment); _env_add_primitive1(_global, "--", _decrement); _env_add_primitive2(_global, "%", _mod); _env_add_primitive(_global, "<", _lt); _env_add_primitive(_global, "<=", _lte); _env_add_primitive(_global, ">", _gt); _env_add_primitive(_global, ">=", _gte); _env_add_primitive(_global, "=", _e); _env_add_primitive2(_global, "cons", _cons); _env_add_primitive1(_global, "car", _car); _env_add_primitive1(_global, "cdr", _cdr); _env_add_primitive1(_global, "null?", _nullp); _env_add_primitive0(_global, "gc", _gc); _env_add_primitive1(_global, "load", _load); _env_add_primitive0(_global, "quit", _quit); _env_add_primitive(_global, "vec-alloc", _vec_alloc); _env_add_primitive(_global, "vec-add", _vec_add); _env_add_primitive1(_global, "vec-length", _vec_length); _env_add_primitive1(_global, "vec-clear", _vec_clear); _env_add_primitive2(_global, "vec-get", _vec_get); _env_add_primitive3(_global, "vec-set", _vec_set); _env_add_primitive0(_global, "map-alloc", _map_alloc); _env_add_primitive3(_global, "map-add", _map_add); _env_add_primitive1(_global, "map-clear", _map_clear); _env_add_primitive1(_global, "map-size", _map_size); _env_add_primitive(_global, "map-find", _map_find); _env_add_primitive2(_global, "map-delete", _map_delete); _env_add_primitive1(_global, "map-keys", _map_keys); _env_add_primitive1(_global, "display", _display); o = _load_imp("prelude.ang", _global); if (ERRORP(o)) /* TODO */ { port_ptr p = port_open_stdout(); obj_print(o, p); port_close(p); } } return _global; }
static char * ICACHE_FLASH_ATTR readRx(RcvMsgBuff *rxBfr) { static int idx = 0; static char bfr[400]; char c; ETS_UART_INTR_DISABLE(); while (rxBfr->count > 0) { c = *(rxBfr->pReadPos); rxBfr->count--; rxBfr->pReadPos++; if (rxBfr->pReadPos == (rxBfr->pRcvMsgBuff + RX_BUFF_SIZE)) { rxBfr->pReadPos = rxBfr->pRcvMsgBuff ; } if (c == '\r' || c == '\n') { if (idx > 0) { // Otherwise ignore blank line bfr[idx] = 0; idx = 0; ETS_UART_INTR_ENABLE(); return bfr; } } else { if (idx < sizeof(bfr)-3) { bfr[idx++] = c; } else { ERRORP("Bfr overflow\n"); } } } ETS_UART_INTR_ENABLE(); return NULL; }
void ICACHE_FLASH_ATTR publishMapping(void) { if (mqttIsConnected()) { char *topic = (char *) os_zalloc(50); char *data = (char *) os_zalloc(500); int idx; if (topic == NULL || data == NULL) { ERRORP("malloc err %s/%s\n", topic, data); startFlash(-1, 50, 50); // fast return; } os_sprintf(topic, "/Raw/%10s/mapping", sysCfg.device_id); os_sprintf(data, "["); for (idx=0; idx<MAP_TEMP_SIZE; idx++) { if (idx != 0) os_sprintf(data + os_strlen(data), ", "); os_sprintf(data + os_strlen(data), "{\"map\":%d,\"name\":\"%s\", \"sensorID\": \"%s\"}", sysCfg.mapping[idx], sysCfg.mappingName[idx], unmappedSensorID(idx)); } os_sprintf(data + os_strlen(data), "]"); if (!MQTT_Publish(mqttClient, topic, data, os_strlen(data), 0, true)) printMQTTstate(); INFOP("%s=>%s\n", topic, data); checkMinHeap(); os_free(topic); os_free(data); } }
void ICACHE_FLASH_ATTR publishError(uint8 err, int info) { static uint8 last_err = 0xff; static int last_info = -1; if (err == last_err && info == last_info) return; // Ignore repeated errors char *topic = (char*) os_malloc(50), *data = (char*) os_malloc(100); if (topic == NULL || data == NULL) { ERRORP("malloc err %s/%s\n", topic, data); startFlash(-1, 50, 50); // fast return; } os_sprintf(topic, (const char*) "/Raw/%s/error", sysCfg.device_id); os_sprintf(data, (const char*) "{ \"error\":%d, \"info\":%d}", err, info); if (mqttIsConnected()) { if (!MQTT_Publish(mqttClient, topic, data, os_strlen(data), 0, 0)) printMQTTstate(); TESTP("********"); } else { TESTP("--------"); } TESTP("%s=>%s\n", topic, data); checkMinHeap(); os_free(topic); os_free(data); }
static bool ICACHE_FLASH_ATTR checkAlloc(void *topic, void *data) { if (topic == NULL || data == NULL) { ERRORP("malloc err %s/%s\n", topic, data); startFlash(-1, 50, 50); // fast if (topic) os_free(topic); return false; } return true; }
static int ICACHE_FLASH_ATTR __attribute__ ((noinline)) init_message(mqtt_connection_t* connection) { if (connection != NULL) { connection->message.length = MQTT_MAX_FIXED_HEADER_SIZE; return MQTT_MAX_FIXED_HEADER_SIZE; } else { ERRORP("MQTT_msg: message not allocated\n"); return 0; } }
static int prepare_data_room(board_t* board, uint32_t length) { struct stat st; assert(NULL != board); ERRORP(-1 == fstat(board->data.fd, &st), "Can't fstat data file."); board->data.st_size = st.st_size; if (board->data.st_size - board->data.used_size < length) { ERRORP(-1 == expand_file(&board->data), "Error happened when expand data file."); } return 0; L_error: return -1; }
//(if cond then &rest else) sexp lisp_if(sexp cond,sexp then_br,sexp else_br,sexp cur_env_sexp){ env *cur_env=cur_env_sexp.val.cur_env; sexp test_result=eval(cond,cur_env); if(ERRORP(cond)){ return cond; } if(isTrue(test_result)){ return eval(then_br,cur_env); } else { return eval(else_br,cur_env); } }
/*************************************************************** Load ***************************************************************/ static obj_ptr _load_imp(cptr file, obj_ptr env) { port_ptr p; obj_ptr o = NIL; p = port_open_input_file(file); while (!port_eof(p)) { o = obj_read(p); if (ERRORP(o)) break; o = obj_eval(o, env); if (ERRORP(o)) break; port_skip_while(p, isspace); } if (ERRORP(o)) error_add_file_info(o, port_name(p), port_line(p)); port_close(p); return o; }
static void ICACHE_FLASH_ATTR startUp() { TESTP("\n%s ( %s - %s ) starting ...\n", "MQTT Bridge", wifi_station_get_hostname(), version); INFOP("wifi_get_phy_mode = %d\n", wifi_get_phy_mode()); // os_timer_disarm(&uartTimer); // os_timer_setfn(&uartTimer, (os_timer_func_t *) uartTimerCb, (void *) 0); // os_timer_arm(&uartTimer, 10 * 1000, true); if ( !system_os_task(backgroundTask, USER_TASK_PRIO_1, taskQueue, QUEUE_SIZE)) ERRORP("Can't set up background task\n"); lastAction = INIT_DONE; }
static void ICACHE_FLASH_ATTR backgroundTask(os_event_t *e) { static RcvMsgBuff *tempRcv = NULL; INFOP("Background task %d\n", e->sig); switch (e->sig) { case EVENT_RX: processRxFunc(tempRcv = (RcvMsgBuff *)e->par); break; case EVENT_RX_OVERFLOW: ERRORP("Rx overflow\n"); processRxFunc((RcvMsgBuff *)e->par); break; // case EVENT_UART_TIMER: // if (tempRcv) // TESTP("UART c %d, r %d, w %d, s %x\n", tempRcv->count, tempRcv->pReadPos, // tempRcv->pWritePos, READ_PERI_REG(UART_INT_CLR(0))); // break; default: ERRORP("Bad background task event %d\n", e->sig); break; } }
static int prepare_index_room(board_t* board) { struct stat st; assert(NULL != board); ERRORP(-1 == fstat(board->index.fd, &st), "Can't fstat index file."); board->index.st_size = st.st_size; if (board->index.st_size - board->index.used_size < 10 * sizeof(article_t)) { ERRORP(-1 == expand_file(&board->index), "Error happened when expand index file."); ERRORP(-1 == write_stat_info(board->index.fd, &board->stat), "Error happend when write stat info."); } return 0; L_error: return -1; }
void ICACHE_FLASH_ATTR publishDeviceInfo(char *version, char *mode, uint8 wifiChannel, uint16 wifiConnectTime, char *bestSSID, uint16 vcc) { if (mqttIsConnected()) { char *topic = (char *) os_zalloc(50); char *data = (char *) os_zalloc(500); int idx; struct ip_info ipConfig; if (topic == NULL || data == NULL) { ERRORP("malloc err %s/%s\n", topic, data); startFlash(-1, 50, 50); // fast return; } wifi_get_ip_info(STATION_IF, &ipConfig); os_sprintf(topic, "/Raw/%10s/info", sysCfg.device_id); os_sprintf(data, "{\"Name\":\"%s\", \"Location\":\"%s\", \"Version\":\"%s(%s)\", " "\"Updates\":%d, \"Inputs\":%d, \"Outputs\":%d, " "\"RSSI\":%d, \"Channel\": %d, \"ConnectTime\": %d, \"Vcc\": %d, ", sysCfg.deviceName, sysCfg.deviceLocation, version, mode, sysCfg.updates, #ifdef INPUTS sysCfg.inputs, #else 0, #endif #ifdef OUTPUTS sysCfg.outputs, #else 0, #endif wifi_station_get_rssi(), wifiChannel, wifiConnectTime, vcc); os_sprintf(data + os_strlen(data), "\"IPaddress\":\"%d.%d.%d.%d\"", IP2STR(&ipConfig.ip.addr)); os_sprintf(data + os_strlen(data), ", \"AP\":\"%s\"", bestSSID); os_sprintf(data + os_strlen(data), ", \"Settings\":["); for (idx = 0; idx < SETTINGS_SIZE; idx++) { if (idx != 0) os_sprintf(data + os_strlen(data), ", "); os_sprintf(data + os_strlen(data), "%d", sysCfg.settings[idx]); } os_sprintf(data + os_strlen(data), "]}"); if (!MQTT_Publish(mqttClient, topic, data, os_strlen(data), 0, true)) printMQTTstate(); INFOP("%s=>%s\n", topic, data); checkMinHeap(); os_free(topic); os_free(data); } }
static void setPirLightActive(enum pir_t pir) { if (PIR1 <= pir && pir <= PIR2) { pirLightStatus[pir] = true; if (pirLightStatus[pir] != oldPirLightstatus[pir]) { TESTP("PIR Lt:%d ", pir); publishSensorData(SENSOR_LIGHT_PIR_ACTIVE1 - 1 + pir, "PIR LIGHT ON", "1"); oldPirLightstatus[pir] = true; } os_timer_disarm(&pirLightTmer[pir]); os_timer_setfn(&pirLightTmer[pir], (os_timer_func_t *) pirLightTimeoutCb, pir); os_timer_arm(&pirLightTmer[pir], sysCfg.settings[SETTING_LIGHT_PIR1_ON_TIME-1+pir]*1000*60, false); // Minutes } else { ERRORP("Bad PIR # %d", pir); } }
void ICACHE_FLASH_ATTR setPirFanActive(enum pir_t pir) { if (PIR1 <= pir && pir <= PIR2) { pirFanStatus[pir] = true; if (pirFanStatus[pir] != oldPirFanstatus[pir]) { TESTP("PIR Fan:%d ", pir); publishSensorData(SENSOR_FAN_PIR_ACTIVE1 - 1 + pir, "PIR FAN ON", "1"); oldPirFanstatus[pir] = true; } os_timer_disarm(&pirFanTmer[pir]); os_timer_setfn(&pirFanTmer[pir], (os_timer_func_t *) pirFanTimeoutCb, pir); os_timer_arm(&pirFanTmer[pir], sysCfg.settings[SETTING_FAN_PIR1_ON_TIME-1+pir]*1000*60, false); // Minutes } else { ERRORP("Bad PIR # %d", pir); } }
/*sexp lisp_defconst(sexp sym_sexp,sexp val_sexp,sexp cur_env_sexp){ sexp code=Cons(spec_sexp(_def),Cons(sym_sexp,Cons(val_sexp,NIL))); eval(code,cur_env_sexp.val.cur_env); }*/ sexp lisp_inc_ref(sexp sym_sexp,sexp cur_env_sexp){ if(!SYMBOLP(sym_sexp)){ return format_type_error("incf","symbol",sym_sexp.tag); } env *cur_env=cur_env_sexp.val.cur_env; symref sym=getSym(cur_env,sym_sexp.val.var->name); if(!sym){ return format_error_sexp("undefined variable %r",sym->name); } sexp temp=lisp_inc(sym->val); if(ERRORP(temp)){ return temp; } else { sym->val=temp; return temp; } }
void ICACHE_FLASH_ATTR publishMapping(void) { #define MSG_SIZE 1200 if (checkClient("publishMapping")) { int idx; char *topic = (char *) os_zalloc(50); char *data = (char *) os_zalloc(MSG_SIZE); if (!checkAlloc(topic, data)) return; os_sprintf(topic, "/Raw/%10s/mapping", sysCfg.device_id); os_sprintf(data, "["); for (idx = 0; idx <= MAP_TEMP_LAST; idx++) { if (os_strlen(unmappedSensorID(idx)) == 0) { struct Temperature *t; getUnmappedTemperature(idx, &t); INFO(dump((void *)t, sizeof(*t));); ERRORP("Missing temperature %d\n", idx); // NB Outside temperature may not yet be received } else { if (os_strlen(data) > (MSG_SIZE - 80)) {
void ICACHE_FLASH_ATTR publishInput(uint8 idx, uint8 val) { if (mqttIsConnected()) { char *topic = (char*) os_malloc(50), *data = (char*) os_malloc(100); if (topic == NULL || data == NULL) { ERRORP("malloc err %s/%s\n", topic, data); startFlash(-1, 50, 50); // fast return; } os_sprintf(topic, (const char*) "/Raw/%s/%d/info", sysCfg.device_id, idx + INPUT_SENSOR_ID_START); os_sprintf(data, (const char*) "{\"Name\":\"IP%d\", \"Type\":\"Input\", \"Value\":\"%d\"}", idx, val); INFOP("%s-->%s", topic, data); if (!MQTT_Publish(mqttClient, topic, data, os_strlen(data), 0, 0)) printMQTTstate(); checkMinHeap(); os_free(topic); os_free(data); } }
void ICACHE_FLASH_ATTR publishDeviceReset(char *version, int lastAction) { if (mqttIsConnected()) { char *topic = (char *) os_zalloc(50); char *data = (char *) os_zalloc(200); int idx; if (topic == NULL || data == NULL) { ERRORP("malloc err %s/%s\n", topic, data); startFlash(-1, 50, 50); // fast return; } os_sprintf(topic, "/Raw/%10s/reset", sysCfg.device_id); os_sprintf(data, "{\"Name\":\"%s\", \"Location\":\"%s\", \"Version\":\"%s\", \"Reason\":%d, \"LastAction\":%d}", sysCfg.deviceName, sysCfg.deviceLocation, version, system_get_rst_info()->reason, lastAction); if (!MQTT_Publish(mqttClient, topic, data, os_strlen(data), 0, false)) printMQTTstate(); INFOP("%s=>%s\n", topic, data); checkMinHeap(); os_free(topic); os_free(data); } }
static void ICACHE_FLASH_ATTR printMQTTstate(void) { ERRORP("State: MQTT-%d, TCP-%d\n", mqttClient->mqtt_state, mqttClient->connState); startFlash(-1, 1000, 1000); }
board_t* board_open(const char* file, char mode) { board_t* board = NULL; char* path = NULL; int readonly; off_t begin; size_t len; long pagesize; assert(NULL != file && ('r' == mode || 'w' == mode)); /* * prepare board_t* pointer to return. */ board = malloc(sizeof(board_t)); ERRORP(NULL == board, "Can't allocate memory for board."); memset(board, 0, sizeof(board_t)); board->data.fd = board->index.fd = -1; board->data.content = board->index.content = MAP_FAILED; board->data.flags = MAP_SHARED; board->index.flags = MAP_SHARED; pagesize = sysconf(_SC_PAGESIZE); board->data.default_win = ALIGN_UP(DEFAULT_DATA_MMAP_WIN, pagesize); board->index.default_win = ALIGN_UP(DEFAULT_INDEX_MMAP_WIN, pagesize); board->data.expand_size = DEFAULT_DATA_EXPAND_SIZE; board->index.expand_size = DEFAULT_INDEX_EXPAND_SIZE; /* * prepare file path for 'board.d'. */ len = strlen(file); assert(len > 0); path = malloc(len + 3); ERRORP(NULL == path, "Can't allocate memory for path."); strcpy(path, file); path[len] = '.'; path[len + 1] = 'd'; path[len + 2] = '\0'; /* * open 'board.d' and 'board.i' */ readonly = 'r' == mode ? 1 : 0; if (readonly) { board->data.fd = open(path, O_RDONLY); ERRORVP(-1 == board->data.fd, "Can't open %s to read", path); board->data.prot = PROT_READ; path[len + 1] = 'i'; board->index.fd = open(path, O_RDONLY); ERRORVP(-1 == board->data.fd, "Can't open %s to read", path); board->index.prot = PROT_READ; } else { board->data.fd = open(path, O_RDWR | O_CREAT, 0644); ERRORVP(-1 == board->data.fd, "Can't open %s to read and write", path); board->data.prot = PROT_READ | PROT_WRITE; path[len + 1] = 'i'; board->index.fd = open(path, O_RDWR | O_CREAT, 0644); ERRORVP(-1 == board->data.fd, "Can't open %s to read and write", path); board->index.prot = PROT_READ | PROT_WRITE; } /* * check data file header and index file header, write if neccessary. */ if (0 != check_and_write_header(board->data.fd, 'd', readonly)) goto L_error; if (0 != check_and_write_header(board->index.fd, 'i', readonly)) goto L_error; /* * check statistics information in the end of index file. */ if (0 != check_stat_info(board)) goto L_error; /* * do memory mapping for data file and index file. */ begin = 0; if (board->data.used_size > board->data.default_win) begin = board->data.used_size - board->data.default_win; if (-1 == slide_mmap_window(&board->data, begin, board->data.default_win)) goto L_error; begin = 0; if (board->index.used_size > board->index.default_win) begin = board->index.used_size - board->index.default_win; if (-1 == slide_mmap_window(&board->index, begin, board->index.default_win)) goto L_error; return board; L_error: board_destroy(board); if (NULL != path) free(path); return NULL; }
static bool checkClient(char *s) { if (mqttIsConnected() && mqttClient != NULL) return true; ERRORP("No client for %s (%lx)\n", s, mqttClient); return false; }
/* * if [begin, begin + size) overlaps the file content, then slide * memory mapping window to cover [begin, begin + size) but never * exceed the file ending. * * returns: * -1 error happened. * 0 requested range is mapped already or doesn't overlap the file content. * 1 [begin, min(begin + size, info->st_size)) is mapped. * * notice: * if successfully mapped, info->offset must not be greater than `begin' * as info->offset must be page aligned, and info->offset + info->length * must be not less than begin + size. if info->length is greater than * info->window, then info->window is adjusted to be equal to info->length. */ static int slide_mmap_window(mmap_info_t* info, off_t begin, size_t size) { off_t pa_offset, end; size_t length; size_t window; char* content; long pagesize; struct stat st; assert(NULL != info && begin >= 0); /* * adjust `end' and `size' to make sure [begin, end) doesn't exceed * the file ending. */ ADD_TO_MAX_NO_WRAP(end, begin, size, UINT32_MAX); if (info->st_size < end) { ERRORP(-1 == fstat(info->fd, &st), "Can't fstat"); info->st_size = st.st_size; if (info->st_size < end) { end = info->st_size; SUB_TO_MIN_NO_WRAP(size, end, begin, 0); } } /* * Is [begin, end) contains valid range? */ if (begin >= end) return -1; /* * Is [begin, end) fully covered by [info->offset, info->window) ? */ if (begin >= info->offset && end <= info->offset + info->window) { DEBUGV("slide_mmap_window(): cached: [%4ld, %4ld) < [%4ld, %4ld).\n", begin, end, info->offset, info->offset + info->window); return 0; } /* * make sure [begin, end) can be covered by memory mapping window. */ pagesize = sysconf(_SC_PAGESIZE); pa_offset = ALIGN_DOWN(begin, pagesize); assert(pa_offset >=0 && pa_offset < info->st_size); /* mmap() as much as possible */ window = MIN(info->default_win, info->st_size); if (end - pa_offset > window) { window = end - pa_offset; } else if (info->st_size - pa_offset < window) { SUB_TO_MIN_NO_WRAP(pa_offset, info->st_size, window, 0); pa_offset = ALIGN_DOWN(begin, pagesize); window = info->st_size - pa_offset; } /* * slide memory mapping window. */ content = mmap(NULL, window, info->prot, info->flags, info->fd, pa_offset); ERRORVP(MAP_FAILED == content, "Can't mmap(offset=%ld, window=%d) to %s", pa_offset, window, info->prot == PROT_READ ? "read" : "read/write"); DEBUGV("slide_mmap_window(offset, window): (%8ld, %8d) => (%8ld, %8d).", info->offset, info->window, pa_offset, window); /* * calculate length of valid data in mapping window. */ length = 0; if (pa_offset < info->used_size) length = MIN(window, info->used_size - pa_offset); DEBUGV("slide_mmap_window(): old length -> new length: %d -> %d.", info->length, length); /* * update mmap info. */ if (MAP_FAILED != info->content) munmap(info->content, info->length); info->content = content; info->offset = pa_offset; info->length = length; info->window = window; return 1; L_error: return -1; }
static int check_stat_info(board_t* board) { struct stat st; /* * initialize st_size fields */ ERRORP(-1 == fstat(board->data.fd, &st), "Can't fstat data file."); board->data.st_size = st.st_size; ERRORP(-1 == fstat(board->index.fd, &st), "Can't fstat index file."); board->index.st_size = st.st_size; /* * check statistics information */ if (st.st_size > sizeof(file_header_t) + sizeof(stat_info_t)) { ssize_t bytes; off_t offset; article_t article; /* read the stat_info_t structure in the end of index file. */ offset = lseek(board->index.fd, -sizeof(stat_info_t), SEEK_END); ERRORP(-1 == offset, "Can't lseek"); bytes = readn(board->index.fd, &board->stat, sizeof(stat_info_t)); ERRORP(sizeof(stat_info_t) != bytes, "Can't read stat info."); ERRORP(board->stat.magic != 0xBEEFDEAD || sizeof(stat_info_t) != board->stat.length, "Corrupted stat info."); /* calculate used_size of index file and check it. */ board->index.used_size = sizeof(file_header_t) + board->stat.count * sizeof(article_t); offset = board->index.used_size - sizeof(article_t); offset = lseek(board->index.fd, offset, SEEK_SET); ERRORP(-1 == offset, "Can't seek in index file."); bytes = readn(board->index.fd, &article, sizeof(article_t)); ERRORP(sizeof(article_t) != bytes, "Can't read the last index item."); ERRORP(0xDEADBEEF != article.magic, "Corrupted index file."); /* calculate used_size of data file and check it. */ offset = article.offset; offset = lseek(board->data.fd, offset, SEEK_SET); ERRORP(-1 == offset, "Can't seek in data file."); bytes = readn(board->data.fd, &article, sizeof(article_t)); ERRORP(sizeof(article_t) != bytes, "Can't read the last article."); ERRORP(0xDEADBEEF != article.magic, "Corrupted data file."); board->data.used_size = offset + article.length; /* check whether the article is the last one in data file. */ if (board->data.used_size + sizeof(article_t) <= board->data.st_size) { bytes = readn(board->data.fd, &article, sizeof(article_t)); ERRORP(sizeof(article_t) != bytes, "Can't read data file."); ERRORP(0xDEADBEEF == article.magic, "Corrupted index file."); } } else { assert(sizeof(file_header_t) == board->data.st_size); board->data.used_size = sizeof(file_header_t); board->index.used_size = sizeof(file_header_t); memset(&board->stat, 0, sizeof(stat_info_t)); board->stat.magic = 0xBEEFDEAD; board->stat.length = sizeof(stat_info_t); } return 0; L_error: return -1; }