OSC_ERR OscGpioConfigImageTrigger(enum EnTriggerConfig enConfig) { struct GPIO_PIN *pPin = &gpio.pins[PIN_FN_EX_TRIGGER_N]; int ret; if(enConfig == TRIGGER_INTERNAL) { /* Pin is lowactive. */ ret = write(pPin->fd, &on, 1); } else if(enConfig == TRIGGER_EXTERNAL_IN2) { /* Pin is lowactive. */ ret = write(pPin->fd, &off, 1); } else { OscLog(ERROR, "%s: Invalid trigger config for this hardware (%d)!\n", __func__, enConfig); return -EINVALID_PARAMETER; } if(unlikely(ret < 0)) { OscLog(ERROR, "%s: Error writing to pin %s (%s)\n", __func__, pPin->pDefConfig->name, strerror(errno)); return -EDEVICE; } gpio.enTriggerConfig = enConfig; return SUCCESS; }
OSC_ERR OscIpcSetParam(const OSC_IPC_CHAN_ID chanID, void *pData, const uint32 paramID, const uint32 paramSize) { struct OSC_IPC_MSG msg; OSC_ERR err; msg.enCmd = CMD_WR_PARAM; msg.paramID = paramID; msg.paramProp = paramSize; /* Input validation */ if(unlikely((chanID >= MAX_NR_IPC_CHANNELS) || (ipc.arybIpcChansBusy[chanID] == FALSE) || (pData == NULL))) { OscLog(ERROR, "%s(%d, 0x%x, %u, %u): Invalid parameter!\n", __func__, chanID, pData, paramID, paramSize); return -EINVALID_PARAMETER; } /* This function only works in blocking mode. */ if(unlikely(ipc.aryIpcChans[chanID].flags & F_IPC_NONBLOCKING)) { OscLog(ERROR, "%s: Only works in blocking mode!\n", __func__); return -EBLOCKING_MODE_ONLY; } /* Send the message. The server will write the requested * data directly to the specified data pointer. */ err = OscIpcSendMsg(chanID, &msg); if(err != SUCCESS) { return err; } err = OscIpcSend(chanID, pData, paramSize); if(err != SUCCESS) { return err; } /* Wait for an acknowledge. As long as the server has not opened * the other side yet, we will receive -ENO_MSG_AVAIL. */ do { err = OscIpcRecvMsg(chanID, &msg); } while(err == -ENO_MSG_AVAIL); if(likely(msg.enCmd == CMD_WR_PARAM_ACK)) { return SUCCESS; } else { /* NACK */ return -ENEGATIVE_ACKNOWLEDGE; } }
void ProcessFrame(uint8 *pRawImg) { OSC_ERR err; enum EnBayerOrder enBayerOrder; err = OscCamGetBayerOrder(&enBayerOrder, 0, 0); if (err != SUCCESS) { OscLog(ERROR, "%s: Error getting bayer order! (%d)\n", __func__, err); return; } /* Use a framework function to debayer the image. */ err = OscVisDebayer(pRawImg, OSC_CAM_MAX_IMAGE_WIDTH, OSC_CAM_MAX_IMAGE_HEIGHT, enBayerOrder, data.u8ResultImage); if (err != SUCCESS) { OscLog(ERROR, "%s: Error debayering image! (%d)\n", __func__, err); return; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* | */ /* | Add your code here */ /* | */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ }
/*********************************************************************//*! * @brief Checks for IPC events, schedules their handling and * acknowledges any executed ones. * * @param pMainState Initalized HSM main state variable. * @return 0 on success or an appropriate error code. *//*********************************************************************/ static OSC_ERR HandleIpcRequests(MainState *pMainState) { OSC_ERR err; uint32 paramId; err = CheckIpcRequests(¶mId); if (err == SUCCESS) { /* We have a request. See to it that it is handled * depending on the state we're in. */ switch(paramId) { case GET_APP_STATE: /* Request for the current state of the application. */ ThrowEvent(pMainState, IPC_GET_APP_STATE_EVT); break; case GET_COLOR_IMG: /* Request for the live image. */ ThrowEvent(pMainState, IPC_GET_COLOR_IMG_EVT); break; case GET_RAW_IMG: /* Request for the live image. */ ThrowEvent(pMainState, IPC_GET_RAW_IMG_EVT); break; case SET_CAPTURE_MODE: /* Set the debayering option. */ ThrowEvent(pMainState, IPC_SET_CAPTURE_MODE_EVT); break; default: OscLog(ERROR, "%s: Unkown IPC parameter ID (%d)!\n", __func__, paramId); data.ipc.enReqState = REQ_STATE_NACK_PENDING; break; } } else if (err == -ENO_MSG_AVAIL) { /* No new message available => do nothing. */ } else { /* Error.*/ OscLog(ERROR, "%s: IPC request error! (%d)\n", __func__, err); return err; } /* Try to acknowledge the new or any old unacknowledged * requests. It may take several tries to succeed.*/ err = AckIpcRequests(); if (err != SUCCESS) { OscLog(ERROR, "%s: IPC acknowledge error! (%d)\n", __func__, err); } return err; }
Msg const *MainState_idle(MainState *me, Msg *msg) { switch (msg->evt) { case ENTRY_EVT: OscLog(INFO, "Enter idle mode.\n"); #ifndef HAS_CPLD /* Set onboard LED green */ OscGpioSetTestLed( TRUE); OscGpioSetTestLedColor(FALSE, TRUE); /* R, G*/ #endif /* !HAS_CPLD */ return 0; case FRAMESEQ_EVT: /* Sleep here for a short while in order not to violate the vertical * blank time of the camera sensor when triggering a new image * right after receiving the old one. This can be removed if some * heavy calculations are done here. */ usleep(1000); return 0; case FRAMEPAR_EVT: return 0; case CMD_GO_IDLE_EVT: data.comm.enReqState = REQ_STATE_ACK_PENDING; return 0; case CMD_GO_ACQ_EVT: if(data.enTriggerMode == TRIG_MODE_INTERNAL) { STATE_TRAN(me, &me->internal); } else if(data.enTriggerMode == TRIG_MODE_EXTERNAL) { STATE_TRAN(me, &me->external); } else { OscLog(ERROR, "%d: Invalid trigger mode configured (%d)!\n", __func__, data.enTriggerMode); data.comm.enReqState = REQ_STATE_NACK_PENDING; return 0; } data.comm.enReqState = REQ_STATE_ACK_PENDING; return 0; case CMD_USE_INTERN_TRIGGER_EVT: /* Switch state to internal capturing mode. */ data.enTriggerMode = TRIG_MODE_INTERNAL; data.comm.enReqState = REQ_STATE_ACK_PENDING; return 0; case CMD_USE_EXTERN_TRIGGER_EVT: /* Switch state to external capturing mode. */ data.enTriggerMode = TRIG_MODE_EXTERNAL; data.comm.enReqState = REQ_STATE_ACK_PENDING; return 0; } return msg; }
OSC_ERR OscGpioSetTestLedColor(uint8 red, uint8 green) { int ret; struct GPIO_PIN *pRed = &gpio.pins[PIN_TESTLED_R_N]; struct GPIO_PIN *pGreen = &gpio.pins[PIN_TESTLED_G_N]; bool bRedOn, bGreenOn; bool bRedPolarity, bGreenPolarity; bRedPolarity = ((pRed->flags & POL_LOWACTIVE) != 0); bGreenPolarity = ((pGreen->flags & POL_LOWACTIVE) != 0); bRedOn = (red ? TRUE : FALSE); bGreenOn = (green ? TRUE : FALSE); /* Color transitions currently not supported. */ ret = write(pRed->fd, ((bRedOn ^ bRedPolarity) ? &on : &off), 1); ret |= write(pGreen->fd, ((bGreenOn ^ bGreenPolarity) ? &on : &off), 1); if(ret < 0) { OscLog(ERROR, "%s: Unable to set LED color (%s)\n", __func__, strerror(errno)); return -EDEVICE; } return SUCCESS; }
OSC_ERR OscGpioWrite(enum EnGpios enGpio, bool bState) { struct GPIO_PIN *pPin = &gpio.pins[enGpio]; bool bLowPolarity; int ret; if(unlikely(!pPin->fd)) { OscLog(ERROR, "%s: No file descriptor for pin %d found. " "This probably " "means that this GPIO is not available on your " "hardware platform.", __func__, enGpio); return -EINVALID_PARAMETER; } /* Sanity check */ if(unlikely(!(pPin->flags & DIR_OUTPUT))) { OscLog(ERROR, "%s: Cannot write to an input (%s)\n", __func__, pPin->pDefConfig->name); return -EINVALID_PARAMETER; } if(pPin->flags & FUN_RESERVED) { OscLog(WARN, "%s: Pin %s is reserved internally and can not " "currently be accessed by the application!\n", __func__, pPin->pDefConfig->name); return -EDEVICE_BUSY; } /* Write to the driver. XOR with the pin polarity to get the correct value to write.*/ bLowPolarity = ((pPin->flags & POL_LOWACTIVE) != 0); if(bState ^ bLowPolarity) { ret = write(pPin->fd, &on, 1); } else { ret = write(pPin->fd, &off, 1); } if(unlikely(ret < 0)) { OscLog(ERROR, "%s: Error writing to pin %s (%s)\n", __func__, pPin->pDefConfig->name, strerror(errno)); return -EDEVICE; } return SUCCESS; }
/*********************************************************************//*! * @brief Set the parameters for the application supplied by the web * interface. * * @return SUCCESS or an appropriate error code otherwise *//*********************************************************************/ static OSC_ERR SetOptions() { OSC_ERR err; struct ARGUMENT_DATA *pArgs = &cgi.args; if (pArgs->bImageType_supplied) { err = OscIpcSetParam(cgi.ipcChan, &pArgs->nImageType, SET_IMAGE_TYPE, sizeof(pArgs->nImageType)); if (err != SUCCESS) { OscLog(DEBUG, "CGI: Error setting option! (%d)\n", err); return err; } } if (pArgs->bThreshold_supplied) { err = OscIpcSetParam(cgi.ipcChan, &pArgs->nThreshold, SET_THRESHOLD, sizeof(pArgs->nThreshold)); if (err != SUCCESS) { OscLog(DEBUG, "CGI: Error setting option! (%d)\n", err); return err; } } if (pArgs->bExposureTime_supplied) { err = OscIpcSetParam(cgi.ipcChan, &pArgs->nExposureTime, SET_EXPOSURE_TIME, sizeof(pArgs->nExposureTime)); if (err != SUCCESS) { OscLog(DEBUG, "CGI: Error setting option! (%d)\n", err); return err; } } if (pArgs->bAddInfo_supplied) { err = OscIpcSetParam(cgi.ipcChan, &pArgs->nAddInfo, SET_ADDINFO, sizeof(pArgs->nAddInfo)); if (err != SUCCESS) { OscLog(DEBUG, "CGI: Error setting option! (%d)\n", err); return err; } } return SUCCESS; }
/*********************************************************************//*! * @brief Query the current state of the application and see what else * we need to get from it * * Depending on the current state of the application, other additional * parameters may be queried. * * @return SUCCESS or an appropriate error code otherwise *//*********************************************************************/ static OSC_ERR QueryApp() { OSC_ERR err; struct OSC_PICTURE pic; /* First, get the current state of the algorithm. */ err = OscIpcGetParam(cgi.ipcChan, &cgi.appState, GET_APP_STATE, sizeof(struct APPLICATION_STATE)); if (err != SUCCESS) { /* This request is defined in all states, and thus must succeed. */ OscLog(ERROR, "CGI: Error querying application! (%d)\n", err); return err; } switch(cgi.appState.enAppMode) { case APP_OFF: /* Algorithm is off, nothing else to do. */ break; case APP_CAPTURE_ON: if (cgi.appState.bNewImageReady) { /* If there is a new image ready, request it from the application. */ err = OscIpcGetParam(cgi.ipcChan, cgi.imgBuf, GET_NEW_IMG, OSC_CAM_MAX_IMAGE_WIDTH/2*OSC_CAM_MAX_IMAGE_HEIGHT/2); if (err != SUCCESS) { OscLog(DEBUG, "CGI: Getting new image failed! (%d)\n", err); return err; } /* Write the image to the RAM file system where it can be picked * up by the webserver on request from the browser. */ pic.width = OSC_CAM_MAX_IMAGE_WIDTH/2; pic.height = OSC_CAM_MAX_IMAGE_HEIGHT/2; pic.type = OSC_PICTURE_GREYSCALE; pic.data = (void*)cgi.imgBuf; return OscBmpWrite(&pic, IMG_FN); } break; default: OscLog(ERROR, "%s: Invalid application mode (%d)!\n", __func__, cgi.appState.enAppMode); break; } return SUCCESS; }
OSC_ERR OscGpioRead(enum EnGpios enGpio, bool *pbState) { struct GPIO_PIN *pPin = &gpio.pins[enGpio]; bool bLowPolarity; char buf; int ret; if(unlikely(!pPin->fd)) { OscLog(ERROR, "%s: No file descriptor for pin %d found. " "This probably " "means that this GPIO is not available on your " "hardware platform.", __func__, enGpio); return -EINVALID_PARAMETER; } if(pPin->flags & FUN_RESERVED) { OscLog(WARN, "%s: Pin %s is reserved internally and can not " "currently be accessed by the application!\n", __func__, pPin->pDefConfig->name); return -EDEVICE_BUSY; } /* Read from the driver. */ ret = read(pPin->fd, &buf, 1); if(unlikely(ret < 0)) { OscLog(ERROR, "%s: Error reading from pin %s (%s)\n", __func__, pPin->pDefConfig->name, strerror(errno)); return -EDEVICE; } /* Get the current pin polarity and calculate the resulting value*/ bLowPolarity = ((pPin->flags & POL_LOWACTIVE) != 0); if(buf != off) { *pbState = !bLowPolarity; } else { *pbState = bLowPolarity; } return SUCCESS; }
/*! * @brief Program entry * * @param argc Command line argument count. * @param argv Command line argument strings. * @return 0 on success */ int main(const int argc, const char ** argv) { OSC_ERR err = SUCCESS; /* This initializes various parts of the framework and the application. */ err = init(argc, argv); if (err != SUCCESS) { OscLog(ERROR, "%s: Initialization failed!(%d)\n", __func__, err); return err; } OscLog(INFO, "Initialization successful!\n"); /* Calls the main loop. This only returns on an error. */ mainLoop(); /* On an error, we unload the framework, before we exit. */ Unload(); return 0; }
/*********************************************************************//*! * @brief Program entry * * @param argc Command line argument count. * @param argv Command line argument strings. * @return 0 on success *//*********************************************************************/ int main(const int argc, const char * argv[]) { OSC_ERR err = SUCCESS; err = init(argc, argv); if (err != SUCCESS) { OscLog(ERROR, "%s: Initialization failed!(%d)\n", __func__, err); return err; } OscLog(INFO, "Initialization successful.\n"); #ifdef HAS_CPLD OscLog(INFO, "CPLD Firmware (Version: %d)\n", (int)data.firmwareRevision); #endif /* HAS_CPLD */ StateControl(); Unload(); return 0; }
/*********************************************************************//*! * @brief Program entry * * @param argc Command line argument count. * @param argv Command line argument strings. * @return 0 on success *//*********************************************************************/ int main(const int argc, const char * argv[]) { OSC_ERR err = SUCCESS; err = init(argc, argv); if (err != SUCCESS) { OscLog(ERROR, "%s: Initialization failed!(%d)\n", __func__, err); return err; } OscLog(INFO, "Initialization successful!\n"); OscLogSetConsoleLogLevel(INFO); OscLogSetFileLogLevel(WARN); StateControl(); Unload(); return 0; }
/*********************************************************************//*! * @brief Host only: Crop a picture to the specified window. * * The contents of the supplied OSC_PICTURE structure are cropped and * written to pDstBuffer. pPic is not changed. * * Host only. * * @param pDstBuffer The destination buffer where the cropped image * is written to. * @param dstBufferSize Size of above destination buffer. * @param pPic Picture to be cropped. * @param pCropWin Window to crop the picture to. * @return SUCCESS or an appropriate error code otherwise *//*********************************************************************/ static OSC_ERR OscCamCropPicture(uint8* pDstBuffer, const uint32 dstBufferSize, const struct OSC_PICTURE *pPic, const struct capture_window *pCropWin) { uint8 *pTSrc, *pTDst; uint32 croppedSize; uint16 colorDepth, bytesPerPixel; uint32 y; uint32 lowY, highY; /* Input validation */ if((pPic == NULL) || (pPic->data == NULL) || (pCropWin == NULL) || (pDstBuffer == NULL) || (dstBufferSize == 0)) { OscLog(ERROR, "%s(0x%x, %u, 0x%x, 0x%x): Invalid parameter!\n", __func__, pDstBuffer, dstBufferSize, pPic, pCropWin); return -EINVALID_PARAMETER; } if((pPic->width < (pCropWin->col_off + pCropWin->width)) || pPic->height < (pCropWin->row_off + pCropWin->height)) { OscLog(ERROR, "%s: Unable to crop image (%dx%d) to (%dx%d @ %d/%d).\n", __func__, pPic->width, pPic->height, pCropWin->width, pCropWin->height, pCropWin->col_off, pCropWin->row_off); return -EPICTURE_TOO_SMALL; } /* Allocate a temporary buffer for the cropped image */ colorDepth = OSC_PICTURE_TYPE_COLOR_DEPTH(pPic->type); bytesPerPixel = colorDepth / 8; croppedSize = pCropWin->width * pCropWin->height * bytesPerPixel; if(croppedSize > dstBufferSize) { OscLog(ERROR, "%s: Specified destination Buffer too small. \ (%d < %d)\n", __func__, dstBufferSize, croppedSize); return -EBUFFER_TOO_SMALL; }
OSC_ERR OscGpioTriggerImage() { int ret; struct GPIO_PIN *pPin = &gpio.pins[PIN_EXPOSURE]; #ifdef TARGET_TYPE_LEANXCAM if(gpio.enTriggerConfig != TRIGGER_INTERNAL) { /* Don't allow internal triggering if external triggering is configured. */ return -EDEVICE_BUSY; } #endif /* Create a pulse on the Exposure pin of the image sensor. Sensor * is triggered by rising flank, so high time should not have to * be too broad.*/ if((pPin->flags & POL_LOWACTIVE) != 0) { /* Lowactive */ ret = write(pPin->fd, &off, 1); /* Rising flank */ } else { ret = write(pPin->fd, &on, 1); /* Rising flank */ } if(unlikely(ret < 0)) { goto exit_fail; } /* Wait until the pin has been set. */ asm("ssync;\n"); if((pPin->flags & POL_LOWACTIVE) != 0) { /* Lowactive */ ret = write(pPin->fd, &on, 1); /* Falling flank */ } else { ret = write(pPin->fd, &off, 1); /* Falling flank */ } if(unlikely(ret < 0)) { goto exit_fail; } /* Wait until the pin has been set. */ asm("ssync;\n"); return SUCCESS; exit_fail: OscLog(ERROR, "%s: Unable to create trigger pulse (%s)\n", __func__, strerror(errno)); return -EDEVICE; }
OSC_ERR SelfTrigger(void) { OSC_ERR err; #ifdef HAS_CPLD err = OscLgxTriggerImage(); #else err = OscGpioTriggerImage(); #endif /* HAS_CPLD */ if (err != SUCCESS) { OscLog(ERROR, "%s: Unable to trigger capture (%d)!\n", __func__, err); } return err; }
OSC_ERR OscGpioSetTestLed(bool bOn) { int ret; struct GPIO_PIN *pPin = &gpio.pins[PIN_TESTLED_N]; ret = write(pPin->fd, (bOn ? &on : &off), 1); if(ret < 0) { OscLog(ERROR, "%s: Unable to set LED (%s)\n", __func__, strerror(errno)); return -EDEVICE; } return SUCCESS; }
OSC_ERR OscGpioToggleTestLed() { int ret; struct GPIO_PIN *pPin = &gpio.pins[PIN_TESTLED_N]; ret = write(pPin->fd, &toggle, 1); if(ret < 0) { OscLog(ERROR, "%s: Unable to toggle LED (%s)\n", __func__, strerror(errno)); return -EDEVICE; } return SUCCESS; }
Msg const *MainState_internal(MainState *me, Msg *msg) { switch (msg->evt) { case ENTRY_EVT: OscLog(INFO, "Enter internal capture mode.\n"); /* Initiate manual triggering. Target dependet. */ SelfTrigger(); return 0; case TRIGGER_EVT: /* Initiate manual triggering. Target dependet. */ SelfTrigger(); return 0; } return msg; }
OSC_ERR OscIpcGetRequest(const OSC_IPC_CHAN_ID chanID, struct OSC_IPC_REQUEST *pRequest) { struct OSC_IPC_MSG msg; OSC_ERR err; /* Input validation */ if(unlikely((chanID >= MAX_NR_IPC_CHANNELS) || (ipc.arybIpcChansBusy[chanID] == FALSE) || (pRequest == NULL))) { OscLog(ERROR, "%s(%d, 0x%x): Invalid parameter!\n", __func__, chanID, pRequest); return -EINVALID_PARAMETER; } err = OscIpcRecvMsg(chanID, &msg); if(err != SUCCESS) { /* Probably -ENO_MSG_AVAILABLE but may also be a * real error. */ return err; } switch(msg.enCmd) { case CMD_RD_PARAM: pRequest->enType = REQ_TYPE_READ; break; case CMD_WR_PARAM: pRequest->enType = REQ_TYPE_WRITE; break; default: /* Must not happen. */ return -EDEVICE; } pRequest->pAddr = (void*)msg.paramProp; pRequest->paramID = msg.paramID; return SUCCESS; }
Msg const *MainState_external(MainState *me, Msg *msg) { switch (msg->evt) { case ENTRY_EVT: OscLog(INFO, "Enter external capture mode.\n"); #ifdef HAS_CPLD /* Enable CPLD counter. */ OscCpldFset(OSC_LGX_CLKDELAY, OSC_LGX_CLKDELAY_ENABLE, OSC_LGX_CLKDELAY_ENABLE); #endif return 0; case EXIT_EVT: #ifdef HAS_CPLD /* Disable CPLD counter. */ OscCpldFset(OSC_LGX_CLKDELAY, OSC_LGX_CLKDELAY_ENABLE, !OSC_LGX_CLKDELAY_ENABLE); #endif return 0; } return msg; }
OSC_ERR OscGpioSetTestLed(bool bOn) { int ret; struct GPIO_PIN *pRed = &gpio.pins[PIN_TESTLED_R_N]; struct GPIO_PIN *pGreen = &gpio.pins[PIN_TESTLED_G_N]; bool bRedPolarity, bGreenPolarity; bRedPolarity = ((pRed->flags & POL_LOWACTIVE) != 0); bGreenPolarity = ((pGreen->flags & POL_LOWACTIVE) != 0); ret = write(pRed->fd, ((bOn ^ bRedPolarity) ? &on : &off), 1); ret |= write(pGreen->fd, ((bOn ^ bGreenPolarity) ? &on : &off), 1); if(ret < 0) { OscLog(ERROR, "%s: Unable to set LED (%s)\n", __func__, strerror(errno)); return -EDEVICE; } return SUCCESS; }
/*********************************************************************//*! * @brief Query the current state of the application and see what else * we need to get from it * * Depending on the current state of the application, other additional * parameters may be queried. * * @return SUCCESS or an appropriate error code otherwise *//*********************************************************************/ static OSC_ERR QueryApp() { OSC_ERR err; /* First, get the current state of the algorithm. */ err = OscIpcGetParam(cgi.ipcChan, &cgi.appState, GET_APP_STATE, sizeof(struct APPLICATION_STATE)); if (err != SUCCESS) { /* This request is defined in all states, and thus must succeed. */ OscLog(ERROR, "CGI: Error querying application! (%d)\n", err); return err; } switch(cgi.appState.enAppMode) { case APP_OFF: /* Algorithm is off, nothing else to do. */ break; case APP_CAPTURE_ON: if (cgi.appState.bNewImageReady) { FILE* F; uint16 r,c; uint8* pData; uint32 dataSiz, i; uint16 oType; /* If there is a new image ready, request it from the application. */ /* We get TWICE the size of an image because metadata might be available */ err = OscIpcGetParam(cgi.ipcChan, cgi.imgBuf, GET_NEW_IMG, NUM_COLORS*nc*nr*2); if (err != SUCCESS) { OscLog(DEBUG, "CGI: Getting new image failed! (%d)\n", err); return err; } //we have to take care of the different ways gdlib treats gray and color data #if NUM_COLORS == 1 //create gd image and ... gdImagePtr im_out = gdImageCreate(nc, nr); //initialize with sensor image for(r = 0; r < nr; r++) { //in case the original image should not be modified replace the following loop by the memcpy statement //memcpy(im_out->pixels[r], cgi.imgBuf+r*nc, nc*sizeof(uint8)); for(c = 0; c < nc; c++) { im_out->pixels[r][c] = (*(cgi.imgBuf+r*nc+c) & 0xfe);//mask out first bit -> only even gray values } } //allocate color palette (255 is red -> we did not change the sensor image!! should rather use a LUT) for(c = 0; c < 256; c++) { if((c%2) && c > 255-2*MAX_NUM_COLORS){ i = (255-c)/2; gdImageColorAllocate (im_out, colorLUT[i][0], colorLUT[i][1], colorLUT[i][2]); } else { gdImageColorAllocate (im_out, c, c, c); } } #else //create gd image and ... gdImagePtr im_out = gdImageCreateTrueColor(nc, nr); //initialize with sensor image for(r = 0; r < nr; r++) { for(c = 0; c < nc; c++) { uint8* p = (cgi.imgBuf+r*3*nc+3*c); im_out->tpixels[r][c] = gdTrueColor(p[2], p[1], p[0]); } } #endif //there might be additional data to be written to image pData = (uint8*) (cgi.imgBuf+NUM_COLORS*nc*nr); memcpy(&dataSiz, pData, sizeof(uint32)); //OscLog(DEBUG, "received %d number of bytes\n", dataSiz); pData += sizeof(uint32);//skip dataSiz if(dataSiz) { i = 0; while(i < dataSiz) { memcpy(&oType, pData+i, sizeof(uint16)); i += sizeof(uint16); switch(oType) { case OBJ_LINE: { struct IMG_LINE imgLine; memcpy(&imgLine, pData+i, sizLine); i += sizLine; //OscLog(DEBUG, "received line (%d,%d)-(%d,%d), color(%d)\n", imgLine.x1, imgLine.y1, imgLine.x2, imgLine.y2, (int) imgLine.color); gdImageLine(im_out, imgLine.x1, imgLine.y1, imgLine.x2, imgLine.y2, colorLoolUp(imgLine.color)); break; } case OBJ_RECT: { struct IMG_RECT imgRect; memcpy(&imgRect, pData+i, sizRect); i += sizRect; //OscLog(DEBUG, "received rect (%d,%d)-(%d,%d), %s, color(%d)\n", imgRect.left, imgRect.bottom, imgRect.right, imgRect.top, imgRect.recFill ? "fill" : "not fill", (int) imgRect.color); if(imgRect.recFill) { gdImageFilledRectangle(im_out, imgRect.left, imgRect.bottom, imgRect.right, imgRect.top, colorLoolUp(imgRect.color)); } else { gdImageRectangle(im_out, imgRect.left, imgRect.bottom, imgRect.right, imgRect.top, colorLoolUp(imgRect.color)); } break; } case OBJ_STRING: { gdFontPtr font = gdFontSmall; struct IMG_STRING imgString; memcpy(&imgString, pData+i, sizString); i += sizString; //OscLog(DEBUG, "received string (%d,%d), font %d, %s, color(%d)\n", imgString.xPos, imgString.yPos, imgString.font, pData+i, imgString.color); switch(imgString.font) { case GIANT: font = gdFontGiant; break; case LARGE: font = gdFontLarge; break; case MEDIUMBOLD: font = gdFontMediumBold; break; case SMALL: font = gdFontSmall; break; case TINY: font = gdFontTiny; break; default: break;//set in definition of font } gdImageString(im_out, font, imgString.xPos, imgString.yPos, pData+i, colorLoolUp(imgString.color)); i += imgString.len; } } } } F = fopen(IMG_FN, "wb"); //gdImageGif(im_out, F); gdImageJpeg(im_out, F, 80); fclose(F); gdImageDestroy(im_out); return SUCCESS; } break; default: OscLog(ERROR, "%s: Invalid application mode (%d)!\n", __func__, cgi.appState.enAppMode); break; } return SUCCESS; }
OSC_ERR SetConfigRegister(void *pMainState, struct CBP_PARAM *pReg) { OSC_ERR err; struct CFG_KEY configKey; struct CFG_VAL_STR strCfg; struct MainState *pHsm = (struct MainState *)pMainState; #ifdef HAS_CPLD uint8 cpldReg; int exposureDelay; #endif /* HAS_CPLD */ #ifdef UNSUPPORTED int i; #endif /* UNSUPPORTED */ switch(pReg->id) { case REG_ID_AQUISITION_MODE: if(pReg->val == 0) { ThrowEvent(pHsm, CMD_GO_IDLE_EVT); break; } if(pReg->val == 1) { ThrowEvent(pHsm, CMD_GO_ACQ_EVT); break; } return -EUNSUPPORTED; case REG_ID_TRIGGER_MODE: if(pReg->val == 0) { ThrowEvent(pHsm, CMD_USE_INTERN_TRIGGER_EVT); break; } if(pReg->val == 1) { ThrowEvent(pHsm, CMD_USE_EXTERN_TRIGGER_EVT); break; } return -EUNSUPPORTED; case REG_ID_EXP_TIME: /* Apply exposure time and store to configuration. */ data.exposureTime = pReg->val; /* Apply value */ err = OscCamSetShutterWidth( data.exposureTime); if( err != SUCCESS) { OscLog(ERROR, "%s: Failed to modify exposure time! (%d)\n", __func__, err); break; } OscLog(INFO, "%s: Exposure time stored and applied to %d us\n", __func__, data.exposureTime); /* Store to configuration. */ configKey.strSection = NULL; configKey.strTag = "EXP"; sprintf(strCfg.str, "%ld", data.exposureTime); err = OscCfgSetStr( data.hConfig, &configKey, strCfg.str); err |= OscCfgFlushContent(data.hConfig); return err; #ifdef UNSUPPORTED /* This code is not yet ported to the new communication scheme and thus unsupported. */ case REG_ID_MAC_ADDR: /* Store Mac/Ip persistent. Applied on next reboot. */ for (i=0; i<6; i++) { macAddr[i] = (uint8)data.cmdpkt.data[i]; } /* Compose strings */ sprintf(strMac, "%02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]); OscLog(INFO, "Set MAC addr environment variable: %s (one time programmable)\n",strMac); /* Write to persistent u-boot environment ethaddr. */ pF = fopen("/tmp/mac", "w"); fprintf(pF, "%s", strMac); fflush(pF); fclose(pF); system("fw_setenv ethaddr `more /tmp/mac`"); case CmdPerspective: /* Apply perspective setting and store to configuration */ data.perspective = (enum EnOscCamPerspective)data.cmdpkt.data[0]; /* Apply to sensor */ err = OscCamSetupPerspective( data.perspective); /* Store to configuration */ configKey.strSection = NULL; configKey.strTag = "PER"; err = OscCamPerspectiveEnum2Str( data.perspective, strCfg.str); err = OscCfgSetStr( data.hConfig, &configKey, strCfg.str); err |= OscCfgFlushContent(data.hConfig); break; #endif /* UNSUPPORTED */ return -EUNSUPPORTED; #ifdef HAS_CPLD case REG_ID_EXP_DELAY: /* Apply exposure delay to CPLD. Keep enable bit as currently set. */ exposureDelay = pReg->val; if (exposureDelay > 99) { OscLog(ERROR, "Invalid exposure delay value (%d). Valid range: 0..99\n", exposureDelay); return -EINVALID_PARAMETER; } /* Store to data struct */ data.exposureDelay = exposureDelay; /* Apply to CPLD. Preserve current enable bit state. */ err = OscCpldRget(OSC_LGX_CLKDELAY, &cpldReg); cpldReg = OSC_LGX_CLKDELAY_ENABLE; if( cpldReg & OSC_LGX_CLKDELAY_ENABLE) { cpldReg = exposureDelay | OSC_LGX_CLKDELAY_ENABLE; } else { cpldReg = exposureDelay; } err |= OscCpldRset(OSC_LGX_CLKDELAY, cpldReg); if( err != SUCCESS) { OscLog(ERROR, "%s: Failed to apply exposure delay to CPLD!\n", __func__); return err; } OscLog(INFO, "%s: Exposure applied to CPLD: %d fine clocks.\n", __func__, data.exposureDelay); return SUCCESS; case REG_ID_STORE_CUR_EXP_DELAY: /* Read current fine clock position from CPLD. Store this offset in * configuration and apply to CPLD exposure delay. */ err = OscCpldRget(OSC_LGX_FASTCLKCOUNT, &cpldReg); exposureDelay = cpldReg; /* Value 0 is reserved with the current CPLD version */ if( 0 == exposureDelay) { exposureDelay++; } OscLog(INFO, "%s: Read current fine clock position from CPLD: %d\n", __func__, exposureDelay); /* Store exposure delay to configuration. */ configKey.strSection = NULL; configKey.strTag = "DEL"; sprintf(strCfg.str, "%d", exposureDelay); err = OscCfgSetStr( data.hConfig, &configKey, strCfg.str); err |= OscCfgFlushContent(data.hConfig); if( err != SUCCESS) { OscLog(ERROR, "%s: Failed to store exposure delay to configuration!\n", __func__); break; } OscLog(INFO, "%s: Exposure delay stored to configuration: %d fine clocks.\n", __func__, exposureDelay); /* Apply delay to CPLD. Preserve the current enable bit state */ err = OscCpldRget(OSC_LGX_CLKDELAY, &cpldReg); cpldReg = OSC_LGX_CLKDELAY_ENABLE; if( cpldReg & OSC_LGX_CLKDELAY_ENABLE) { cpldReg = exposureDelay | OSC_LGX_CLKDELAY_ENABLE; } else { cpldReg = exposureDelay; } err |= OscCpldRset(OSC_LGX_CLKDELAY, cpldReg); if( err != SUCCESS) { OscLog(ERROR, "%s: Failed to apply exposure delay to CPLD!\n", __func__); break; } OscLog(INFO, "%s: Exposure applied to CPLD: %d fine clocks.\n", __func__, exposureDelay); break; #endif /* HAS_CPLD */ default: OscLog(WARN, "%s: Invalid register (%#x)!\n", __func__, pReg->id); return -EUNSUPPORTED; } /* Evaluate the success or failure of the commands that invoked the state machine. */ if(data.comm.enReqState == REQ_STATE_ACK_PENDING) { /* Success. */ return SUCCESS; } else if(data.comm.enReqState == REQ_STATE_NACK_PENDING) { return -EDEVICE; } else { OscLog(ERROR, "%s: Change of register %d was not handled by the state machine!\n", __func__, pReg->id); return -EDEVICE; } }
OSC_ERR StateControl( void) { OSC_ERR err; MainState mainState; uint8 *pCurRawImg = NULL; /* Setup main state machine. Start with idle mode. */ MainStateConstruct(&mainState); HsmOnStart((Hsm *)&mainState); /*----------- infinite main loop */ while( TRUE) { /*----------- wait for captured picture */ while (TRUE) { /*----------- Alternating a) check for new connections * b) check for commands (and do process) * c) check for available picture */ err = Comm_AcceptConnections(&data.comm, ACCEPT_CONNS_TIMEOUT); if(err != SUCCESS && err != -ETIMEOUT) { OscLog(ERROR, "%s: Error accepting new connections (%d)!\n", __func__, err); } err = Comm_HandleCommands(&data.comm, &mainState, GET_CMDS_TIMEOUT); if(err != SUCCESS && err != -ETIMEOUT) { OscLog(ERROR, "%s: Error handling commands (%d)!\n", __func__, err); } else if(err == SUCCESS) { OscLog(INFO, "Command received.\n"); } err = OscCamReadPicture(OSC_CAM_MULTI_BUFFER, &pCurRawImg, 0, CAMERA_TIMEOUT); if ((err != -ETIMEOUT) ||(err != -ENO_CAPTURE_STARTED) ) { /* Anything other than a timeout or no pending capture means that we should * stop trying and analyze the situation. */ break; } } if( err == SUCCESS) /* only if breaked due to CamReadPic() */ { data.pCurRawImg = pCurRawImg; OscLog(DEBUG, "---image available\n"); } else { pCurRawImg = NULL; } /*----------- process frame by state engine (pre-setup) Sequentially with next capture */ if( pCurRawImg) { ThrowEvent(&mainState, FRAMESEQ_EVT); } /*----------- prepare next capture */ if( pCurRawImg) { err = OscCamSetupCapture( OSC_CAM_MULTI_BUFFER); if (err != SUCCESS) { OscLog(ERROR, "%s: Unable to setup capture (%d)!\n", __func__, err); break; } } /*----------- do self-triggering (if required) */ ThrowEvent(&mainState, TRIGGER_EVT); /*----------- process frame by state engine (post-setup) Parallel with next capture */ if( pCurRawImg) { ThrowEvent(&mainState, FRAMEPAR_EVT); } } /* end while ever */ return SUCCESS; }
Msg const *MainState_capture(MainState *me, Msg *msg) { OSC_ERR err; uint8 *pDummyImg = NULL; uint32 imgSize; switch (msg->evt) { case ENTRY_EVT: OscLog(INFO, "Enter generic capture mode.\n"); #ifndef HAS_CPLD /* Set onboard LED red */ OscGpioSetTestLed( TRUE); OscGpioSetTestLedColor(TRUE, FALSE); /* R, G*/ #endif /* !HAS_CPLD */ OscLog(INFO, "Setup capture\n"); err = OscCamSetupCapture( OSC_CAM_MULTI_BUFFER); if (err != SUCCESS) { OscLog(ERROR, "%s: Unable to setup initial capture (%d)!\n", __func__, err); } return 0; case FRAMESEQ_EVT: /* Fill out the feed header. */ data.comm.feedHdr.seqNr++; /* We need the uptime in milliseconds. */ data.comm.feedHdr.timeStamp = (uint32)(OscSupCycToMilliSecs(OscSupCycGet64())); data.comm.feedHdr.imgWidth = OSC_CAM_MAX_IMAGE_WIDTH; data.comm.feedHdr.imgHeight = OSC_CAM_MAX_IMAGE_HEIGHT; #ifdef TARGET_TYPE_LEANXCAM data.comm.feedHdr.pixFmt = V4L2_PIX_FMT_GREY; imgSize = data.comm.feedHdr.imgWidth * data.comm.feedHdr.imgHeight * 1; #endif /* TARGET_TYPE_LEANXCAM */ #ifdef TARGET_TYPE_INDXCAM data.comm.feedHdr.pixFmt = V4L2_PIX_FMT_SBGGR8; imgSize = data.comm.feedHdr.imgWidth * data.comm.feedHdr.imgHeight * 1; #endif /* TARGET_TYPE_INDXCAM */ /* Send the image to the host. */ Comm_SendImage(&data.comm, data.pCurRawImg, imgSize, &data.comm.feedHdr); return 0; case FRAMEPAR_EVT: return 0; case CMD_GO_IDLE_EVT: /* Read picture until no more capture is active.Always use self-trigg*/ err = SUCCESS; while(err != -ENO_CAPTURE_STARTED) { SelfTrigger(); err = OscCamReadPicture(OSC_CAM_MULTI_BUFFER, &pDummyImg, 0, CAMERA_TIMEOUT); OscLog(DEBUG, "%s: Removed picture from queue! (%d)\n", __func__, err); } STATE_TRAN(me, &me->idle); data.comm.enReqState = REQ_STATE_ACK_PENDING; return 0; case CMD_GO_ACQ_EVT: data.comm.enReqState = REQ_STATE_ACK_PENDING; return 0; case CMD_USE_INTERN_TRIGGER_EVT: case CMD_USE_EXTERN_TRIGGER_EVT: /* Not supported in acquisition mode. */ data.comm.enReqState = REQ_STATE_NACK_PENDING; return 0; case EXIT_EVT: /* Read picture until no more capture is active. Always use self-trigg*/ err = SUCCESS; while(err != -ENO_CAPTURE_STARTED) { SelfTrigger(); err = OscCamReadPicture(OSC_CAM_MULTI_BUFFER, &pDummyImg, 0, CAMERA_TIMEOUT); OscLog(DEBUG, "%s: Removed picture from queue! (%d)\n", __func__, err); } return 0; } return msg; }
/*********************************************************************//*! * @brief The main program * * Opens the camera and reads pictures as fast as possible * Makes a debayering of the image * Writes the debayered image to a buffer which can be read by * TCP clients on Port 8111. Several concurrent clients are allowed. * The simplest streaming video client looks like this: * * nc 192.168.1.10 8111 | mplayer - -demuxer rawvideo -rawvideo w=376:h=240:format=bgr24:fps=100 * * Writes every 10th picture to a .jpg file in the Web Server Directory *//*********************************************************************/ int main(const int argc, const char * argv[]) { struct OSC_PICTURE calcPic; struct OSC_PICTURE rawPic; unsigned char *tmpbuf; int loops=0; int numalarm=0; char filename[100]; initSystem(&sys); ip_start_server(); /* setup variables */ rawPic.width = OSC_CAM_MAX_IMAGE_WIDTH; rawPic.height = OSC_CAM_MAX_IMAGE_HEIGHT; rawPic.type = OSC_PICTURE_GREYSCALE; /* calcPic width, height etc. are set in the debayering algos */ calcPic.data = malloc(3 * OSC_CAM_MAX_IMAGE_WIDTH * OSC_CAM_MAX_IMAGE_HEIGHT); if (calcPic.data == 0) fatalerror("Did not get memory\n"); tmpbuf = malloc(500000); if (tmpbuf == 0) fatalerror("Did not get memory\n"); #if defined(OSC_TARGET) /* Take a picture, first time slower ;-) */ usleep(10000); OscGpioTriggerImage(); usleep(10000); OscLog(DEBUG,"Triggered CAM "); #endif while(true) { OscCamReadPicture(OSC_CAM_MULTI_BUFFER, (void *) &rawPic.data, 0, 0); /* Take a picture */ usleep(2000); OscCamSetupCapture(OSC_CAM_MULTI_BUFFER); #if defined(OSC_TARGET) OscGpioTriggerImage(); #else usleep(10000); #endif if (is_alarm(&rawPic)) { OscGpioSetTestLed(TRUE); printf("alarm\n"); sprintf(filename, "/home/httpd/alarm_pic%02i.jpg", numalarm%16); writeJPG(&calcPic, tmpbuf, filename); numalarm++; } else { OscGpioSetTestLed(FALSE); } fastdebayerBGR(rawPic, &calcPic, NULL); ip_send_all((char *)calcPic.data, calcPic.width*calcPic.height* OSC_PICTURE_TYPE_COLOR_DEPTH(calcPic.type)/8); loops+=1; if (loops%20 == 0) { writeJPG(&calcPic, tmpbuf, "/home/httpd/liveimage.jpg"); } ip_do_work(); } ip_stop_server(); cleanupSystem(&sys); return 0; } /* main */
/*********************************************************************//*! * @brief Split the supplied URI string into arguments and parse them. * * Matches the argument string with the arguments list (args) and fills in * their values. Unknown arguments provoke an error, but missing * arguments are just ignored. * * @param strSrc The argument string. * @param srcLen The length of the argument string. * @return SUCCESS or an appropriate error code otherwise *//*********************************************************************/ static OSC_ERR CGIParseArguments() { char buffer[1024]; /* Intialize all arguments as 'not supplied' */ for (int i = 0; i < sizeof args / sizeof (struct ARGUMENT); i += 1) { *args[i].pbSupplied = false; } while (fgets (buffer, sizeof buffer, stdin)) { struct ARGUMENT *pArg = NULL; char * key, * value = strchr(buffer, ':'); if (value == NULL) { OscLog(ERROR, "%s: Invalid line: \"%s\"\n", __func__, buffer); return -EINVALID_PARAMETER; } *value = 0; value += 1; key = strtrim(buffer); value = strtrim(value); OscLog(INFO, "obtained key: %s, and Value: %s\n", key, value); for (int i = 0; i < sizeof(args)/sizeof(struct ARGUMENT); i += 1) { if (strcmp(args[i].strName, key) == 0) { pArg = args + i; break; } } if (pArg == NULL) { OscLog(ERROR, "%s: Unknown argument encountered: \"%s\"\n", __func__, key); return -EINVALID_PARAMETER; } else { if (pArg->enType == STRING_ARG) { // FIXME: Could someone fix this buffer overflow? strcpy((char *) pArg->pData, value); } else if (pArg->enType == INT_ARG) { if (sscanf(value, "%d", (int *) pArg->pData) != 1) { OscLog(ERROR, "%s: Unable to parse int value of variable \"%s\" (%s)!\n", __func__, pArg->strName, value); return -EINVALID_PARAMETER; } } else if (pArg->enType == SHORT_ARG) { if (sscanf(value, "%hd", (short *) pArg->pData) != 1) { OscLog(ERROR, "%s: Unable to parse short value of variable \"%s\" (%s)!\n", __func__, pArg->strName, value); return -EINVALID_PARAMETER; } } else if (pArg->enType == BOOL_ARG) { if (strcmp(value, "true") == 0) { *((bool *) pArg->pData) = true; } else if (strcmp(value, "false") == 0) { *((bool *) pArg->pData) = false; } else { OscLog(ERROR, "CGI %s: Unable to parse boolean value of variable \"%s\" (%s)!\n", __func__, pArg->strName, value); return -EINVALID_PARAMETER; } } if (pArg->pbSupplied != NULL) *pArg->pbSupplied = true; } } return SUCCESS; }
/*********************************************************************//*! * @brief Checks for IPC events, schedules their handling and * acknowledges any executed ones. * * @param pMainState Initalized HSM main state variable. * @return 0 on success or an appropriate error code. *//*********************************************************************/ static OSC_ERR HandleIpcRequests(MainState *pMainState) { OSC_ERR err; uint32 paramId; struct IPC_DATA *pIpc = &data.ipc; struct OSC_IPC_REQUEST *pReq = &pIpc->req; err = CheckIpcRequests(¶mId); if (err == SUCCESS) { /* We have a request. See to it that it is handled * depending on the state we're in. */ switch(paramId) { case GET_APP_STATE: /* Request for the current state of the application. */ ThrowEvent(pMainState, IPC_GET_APP_STATE_EVT); break; case GET_NEW_IMG: /* Request for the live image. */ ThrowEvent(pMainState, IPC_GET_NEW_IMG_EVT); break; case SET_IMAGE_TYPE: { /* Set the new image type. */ unsigned int ImgTyp = *((unsigned int*)data.ipc.req.pAddr); if(MAX_NUM_IMG <= ImgTyp) { OscLog(ERROR, "%obtained unknown image type: %u! Will leave unchanged\n", data.ipc.state.nImageType); } else { data.ipc.state.nImageType = ImgTyp; ThrowEvent(pMainState, IPC_SET_IMAGE_TYPE_EVT); } break; } case SET_EXPOSURE_TIME: // a new exposure time was given if(data.ipc.state.nExposureTime != *((int*)pReq->pAddr)) { data.nExposureTimeChanged = true; data.ipc.state.nExposureTime = *((int*)pReq->pAddr); } data.ipc.enReqState = REQ_STATE_ACK_PENDING;//we return immediately break; case SET_THRESHOLD: // a new exposure time was given if(data.ipc.state.nThreshold != *((int*)pReq->pAddr)) { data.ipc.state.nThreshold = *((int*)pReq->pAddr); } data.ipc.enReqState = REQ_STATE_ACK_PENDING;//we return immediately break; default: OscLog(ERROR, "%s: Unkown IPC parameter ID (%d)!\n", __func__, paramId); data.ipc.enReqState = REQ_STATE_NACK_PENDING; break; } } else if (err == -ENO_MSG_AVAIL) { /* No new message available => do nothing. */ } else { /* Error.*/ OscLog(ERROR, "%s: IPC request error! (%d)\n", __func__, err); return err; } /* Try to acknowledge the new or any old unacknowledged * requests. It may take several tries to succeed.*/ err = AckIpcRequests(); if (err != SUCCESS) { OscLog(ERROR, "%s: IPC acknowledge error! (%d)\n", __func__, err); } return err; }
OSC_ERR OscIpcAckRequest(const OSC_IPC_CHAN_ID chanID, const struct OSC_IPC_REQUEST *pRequest, const bool bSucceeded) { struct OSC_IPC_MSG msg; OSC_ERR err; /* Input validation */ if(unlikely((chanID >= MAX_NR_IPC_CHANNELS) || (ipc.arybIpcChansBusy[chanID] == FALSE) || (pRequest == NULL))) { OscLog(ERROR, "%s(%d, 0x%x, %d): Invalid parameter!\n", __func__, chanID, pRequest, bSucceeded); return -EINVALID_PARAMETER; } /* Fill out the acknowledge message structure */ msg.paramProp = (uint32)pRequest->pAddr; msg.paramID = pRequest->paramID; if(likely(bSucceeded == TRUE)) { switch(pRequest->enType) { case REQ_TYPE_READ: msg.enCmd = CMD_RD_PARAM_ACK; break; case REQ_TYPE_WRITE: msg.enCmd = CMD_WR_PARAM_ACK; break; default: return -EINVALID_PARAMETER; } } else { switch(pRequest->enType) { case REQ_TYPE_READ: msg.enCmd = CMD_RD_PARAM_NACK; break; case REQ_TYPE_WRITE: msg.enCmd = CMD_WR_PARAM_NACK; break; default: return -EINVALID_PARAMETER; } } /* Send the acknowledge. This call may return -ETRY_AGAIN, if * the client on the other side of the FIFO did not open the * FIFO for reading yet. We pass it on and leave it to the caller * to try it again later. */ err = OscIpcSendMsg(chanID, &msg); if(err != SUCCESS) { if(err != -ETRY_AGAIN) { OscLog(ERROR, "%s: Failed to send acknowledge! (%d)\n", __func__, err); } return err; } return SUCCESS; }