static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type) { struct saa7146_fh *fh = __fh; int err; DEB_D("VIDIOC_STREAMON, type:%d\n", type); err = video_begin(fh); if (err) return err; if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) return videobuf_streamon(&fh->video_q); if (type == V4L2_BUF_TYPE_VBI_CAPTURE) return videobuf_streamon(&fh->vbi_q); return -EINVAL; }
static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct saa7146_fh *fh = file->private_data; struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; ssize_t ret = 0; DEB_EE(("called.\n")); if ((vv->video_status & STATUS_CAPTURE) != 0) { /* fixme: should we allow read() captures while streaming capture? */ if (vv->video_fh == fh) { DEB_S(("already capturing.\n")); return -EBUSY; } DEB_S(("already capturing in another open.\n")); return -EBUSY; } ret = video_begin(fh); if( 0 != ret) { goto out; } ret = videobuf_read_one(&fh->video_q , data, count, ppos, file->f_flags & O_NONBLOCK); if (ret != 0) { video_end(fh, file); } else { ret = video_end(fh, file); } out: /* restart overlay if it was active before */ if (vv->ov_suspend != NULL) { saa7146_start_preview(vv->ov_suspend); vv->ov_suspend = NULL; } return ret; }
int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) { struct saa7146_fh *fh = file->private_data; struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; int err = 0, result = 0, ee = 0; struct saa7146_use_ops *ops; struct videobuf_queue *q; /* check if extension handles the command */ for(ee = 0; dev->ext_vv_data->ioctls[ee].flags != 0; ee++) { if( cmd == dev->ext_vv_data->ioctls[ee].cmd ) break; } if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_EXCLUSIVE) ) { DEB_D(("extension handles ioctl exclusive.\n")); result = dev->ext_vv_data->ioctl(fh, cmd, arg); return result; } if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_BEFORE) ) { DEB_D(("extension handles ioctl before.\n")); result = dev->ext_vv_data->ioctl(fh, cmd, arg); if( -EAGAIN != result ) { return result; } } /* fixme: add handle "after" case (is it still needed?) */ switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: { ops = &saa7146_video_uops; q = &fh->video_q; break; } case V4L2_BUF_TYPE_VBI_CAPTURE: { ops = &saa7146_vbi_uops; q = &fh->vbi_q; break; } default: BUG(); return 0; } switch (cmd) { case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; memset(cap,0,sizeof(*cap)); DEB_EE(("VIDIOC_QUERYCAP\n")); strcpy(cap->driver, "saa7146 v4l2"); strlcpy(cap->card, dev->ext->name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); cap->version = SAA7146_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; cap->capabilities |= dev->ext_vv_data->capabilities; return 0; } case VIDIOC_G_FBUF: { struct v4l2_framebuffer *fb = arg; DEB_EE(("VIDIOC_G_FBUF\n")); *fb = vv->ov_fb; fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; return 0; } case VIDIOC_S_FBUF: { struct v4l2_framebuffer *fb = arg; struct saa7146_format *fmt; DEB_EE(("VIDIOC_S_FBUF\n")); if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) return -EPERM; /* check args */ fmt = format_by_fourcc(dev,fb->fmt.pixelformat); if (NULL == fmt) { return -EINVAL; } /* planar formats are not allowed for overlay video, clipping and video dma would clash */ if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",(char *)&fmt->pixelformat)); } /* check if overlay is running */ if (IS_OVERLAY_ACTIVE(fh) != 0) { if (vv->video_fh != fh) { DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n")); return -EBUSY; } } down(&dev->lock); /* ok, accept it */ vv->ov_fb = *fb; vv->ov_fmt = fmt; if (0 == vv->ov_fb.fmt.bytesperline) vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width*fmt->depth/8; up(&dev->lock); return 0; } case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *f = arg; int index; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OVERLAY: { index = f->index; if (index < 0 || index >= NUM_FORMATS) { return -EINVAL; } memset(f,0,sizeof(*f)); f->index = index; strlcpy(f->description,formats[index].name,sizeof(f->description)); f->pixelformat = formats[index].pixelformat; break; } default: return -EINVAL; } DEB_EE(("VIDIOC_ENUM_FMT: type:%d, index:%d\n",f->type,f->index)); return 0; } case VIDIOC_QUERYCTRL: { const struct v4l2_queryctrl *ctrl; struct v4l2_queryctrl *c = arg; if ((c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) && (c->id < V4L2_CID_PRIVATE_BASE || c->id >= V4L2_CID_PRIVATE_LASTP1)) return -EINVAL; ctrl = ctrl_by_id(c->id); if( NULL == ctrl ) { return -EINVAL; /* c->flags = V4L2_CTRL_FLAG_DISABLED; return 0; */ } DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n",c->id)); *c = *ctrl; return 0; } case VIDIOC_G_CTRL: { DEB_EE(("VIDIOC_G_CTRL\n")); return get_control(fh,arg); } case VIDIOC_S_CTRL: { DEB_EE(("VIDIOC_S_CTRL\n")); err = set_control(fh,arg); return err; } case VIDIOC_G_PARM: { struct v4l2_streamparm *parm = arg; if( parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ) { return -EINVAL; } memset(&parm->parm.capture,0,sizeof(struct v4l2_captureparm)); parm->parm.capture.readbuffers = 1; // fixme: only for PAL! parm->parm.capture.timeperframe.numerator = 1; parm->parm.capture.timeperframe.denominator = 25; return 0; } case VIDIOC_G_FMT: { struct v4l2_format *f = arg; DEB_EE(("VIDIOC_G_FMT\n")); return g_fmt(fh,f); } case VIDIOC_S_FMT: { struct v4l2_format *f = arg; DEB_EE(("VIDIOC_S_FMT\n")); return s_fmt(fh,f); } case VIDIOC_TRY_FMT: { struct v4l2_format *f = arg; DEB_EE(("VIDIOC_TRY_FMT\n")); return try_fmt(fh,f); } case VIDIOC_G_STD: { v4l2_std_id *id = arg; DEB_EE(("VIDIOC_G_STD\n")); *id = vv->standard->id; return 0; } /* the saa7146 supfhrts (used in conjunction with the saa7111a for example) PAL / NTSC / SECAM. if your hardware does not (or does more) -- override this function in your extension */ case VIDIOC_ENUMSTD: { struct v4l2_standard *e = arg; if (e->index < 0 ) return -EINVAL; if( e->index < dev->ext_vv_data->num_stds ) { DEB_EE(("VIDIOC_ENUMSTD: index:%d\n",e->index)); v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name); return 0; } return -EINVAL; } case VIDIOC_S_STD: { v4l2_std_id *id = arg; int found = 0; int i, err; DEB_EE(("VIDIOC_S_STD\n")); if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) { DEB_D(("cannot change video standard while streaming capture is active\n")); return -EBUSY; } if ((vv->video_status & STATUS_OVERLAY) != 0) { vv->ov_suspend = vv->video_fh; err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ if (0 != err) { DEB_D(("suspending video failed. aborting\n")); return err; } } down(&dev->lock); for(i = 0; i < dev->ext_vv_data->num_stds; i++) if (*id & dev->ext_vv_data->stds[i].id) break; if (i != dev->ext_vv_data->num_stds) { vv->standard = &dev->ext_vv_data->stds[i]; if( NULL != dev->ext_vv_data->std_callback ) dev->ext_vv_data->std_callback(dev, vv->standard); found = 1; } up(&dev->lock); if (vv->ov_suspend != NULL) { saa7146_start_preview(vv->ov_suspend); vv->ov_suspend = NULL; } if( 0 == found ) { DEB_EE(("VIDIOC_S_STD: standard not found.\n")); return -EINVAL; } DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n",vv->standard->name)); return 0; } case VIDIOC_OVERLAY: { int on = *(int *)arg; int err = 0; DEB_D(("VIDIOC_OVERLAY on:%d\n",on)); if (on != 0) { err = saa7146_start_preview(fh); } else { err = saa7146_stop_preview(fh); } return err; } case VIDIOC_REQBUFS: { struct v4l2_requestbuffers *req = arg; DEB_D(("VIDIOC_REQBUFS, type:%d\n",req->type)); return videobuf_reqbufs(q,req); } case VIDIOC_QUERYBUF: { struct v4l2_buffer *buf = arg; DEB_D(("VIDIOC_QUERYBUF, type:%d, offset:%d\n",buf->type,buf->m.offset)); return videobuf_querybuf(q,buf); } case VIDIOC_QBUF: { struct v4l2_buffer *buf = arg; int ret = 0; ret = videobuf_qbuf(q,buf); DEB_D(("VIDIOC_QBUF: ret:%d, index:%d\n",ret,buf->index)); return ret; } case VIDIOC_DQBUF: { struct v4l2_buffer *buf = arg; int ret = 0; ret = videobuf_dqbuf(q,buf,file->f_flags & O_NONBLOCK); DEB_D(("VIDIOC_DQBUF: ret:%d, index:%d\n",ret,buf->index)); return ret; } case VIDIOC_STREAMON: { int *type = arg; DEB_D(("VIDIOC_STREAMON, type:%d\n",*type)); err = video_begin(fh); if( 0 != err) { return err; } err = videobuf_streamon(q); return err; } case VIDIOC_STREAMOFF: { int *type = arg; DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type)); /* ugly: we need to copy some checks from video_end(), because videobuf_streamoff() relies on the capture running. check and fix this */ if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { DEB_S(("not capturing.\n")); return 0; } if (vv->video_fh != fh) { DEB_S(("capturing, but in another open.\n")); return -EBUSY; } err = videobuf_streamoff(q); if (0 != err) { DEB_D(("warning: videobuf_streamoff() failed.\n")); video_end(fh, file); } else { err = video_end(fh, file); } return err; } case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; struct videobuf_queue *q; int i; /* fixme: number of capture buffers and sizes for v4l apps */ int gbuffers = 2; int gbufsize = 768*576*4; DEB_D(("VIDIOCGMBUF \n")); q = &fh->video_q; down(&q->lock); err = videobuf_mmap_setup(q,gbuffers,gbufsize, V4L2_MEMORY_MMAP); if (err < 0) { up(&q->lock); return err; } memset(mbuf,0,sizeof(*mbuf)); mbuf->frames = gbuffers; mbuf->size = gbuffers * gbufsize; for (i = 0; i < gbuffers; i++) mbuf->offsets[i] = i * gbufsize; up(&q->lock); return 0; } default: return v4l_compat_translate_ioctl(inode,file,cmd,arg, saa7146_video_do_ioctl); } return 0; }
void tox_message(uint8_t tox_message_id, uint16_t param1, uint16_t param2, void *data) { switch(tox_message_id) { case DHT_CONNECTED: { /* param1: connection status (1 = connected, 0 = disconnected) */ tox_connected = param1; redraw(); break; } case DNS_RESULT: { /* param1: result (0 = failure, 1 = success) * data: resolved tox id (if successful) */ if(param1) { friend_addid(data, edit_addmsg.data, edit_addmsg.length); } else { addfriend_status = ADDF_BADNAME; } free(data); redraw(); break; } case OPEN_FILES: { tox_postmessage(TOX_SENDFILES, param1, param2, data); break; } case SAVE_FILE: { tox_postmessage(TOX_ACCEPTFILE, param1, param2, data); break; } case NEW_AUDIO_IN_DEVICE: { if(UI_STRING_ID_INVALID == param1) { list_dropdown_add_hardcoded(&dropdown_audio_in, data, data); } else { list_dropdown_add_localized(&dropdown_audio_in, param1, data); } if (loaded_audio_in_device != 0 && (dropdown_audio_in.dropcount - 1) == loaded_audio_in_device) { toxaudio_postmessage(AUDIO_SET_INPUT, 0, 0, data); dropdown_audio_in.selected = loaded_audio_in_device; loaded_audio_in_device = 0; } break; } case NEW_AUDIO_OUT_DEVICE: { list_dropdown_add_hardcoded(&dropdown_audio_out, data, data); if (loaded_audio_out_device != 0 && (dropdown_audio_out.dropcount - 1) == loaded_audio_out_device) { toxaudio_postmessage(AUDIO_SET_OUTPUT, 0, 0, data); dropdown_audio_out.selected = loaded_audio_out_device; loaded_audio_out_device = 0; } break; } case NEW_VIDEO_DEVICE: { if(UI_STRING_ID_INVALID == param1) { // Device name is a hardcoded string. // data is a pointer to a buffer, that contains device handle pointer, // followed by device name string. list_dropdown_add_hardcoded(&dropdown_video, data + sizeof(void*), *(void**)data); } else { // Device name is localized with param1 containing UI_STRING_ID. // data is device handle pointer. list_dropdown_add_localized(&dropdown_video, param1, data); } //param2 == true, if this device will be chosen by video detecting code. if(param2) { dropdown_video.selected = dropdown_video.over = (dropdown_video.dropcount - 1); } break; } case FRIEND_REQUEST: { /* data: pointer to FRIENDREQ structure */ list_addfriendreq(data); break; } case FRIEND_ADD: { /* confirmation that friend has been added to friend list (add) */ if(param1) { /* friend was not added */ addfriend_status = param2; } else { /* friend was added */ edit_addid.length = 0; edit_addmsg.length = 0; FRIEND *f = &friend[param2]; friends++; f->msg.scroll = 1.0; memcpy(f->cid, data, sizeof(f->cid)); friend_setname(f, NULL, 0); list_addfriend(f); addfriend_status = ADDF_SENT; } free(data); redraw(); break; } case FRIEND_ACCEPT: { /* confirmation that friend has been added to friend list (accept) */ if(!param1) { FRIEND *f = &friend[param2]; FRIENDREQ *req = data; friends++; memcpy(f->cid, req->id, sizeof(f->cid)); friend_setname(f, NULL, 0); list_addfriend2(f, req); redraw(); } free(data); break; } case FRIEND_DEL: { friend_free(data); friends--; break; } case FRIEND_MESSAGE: { friend_addmessage(&friend[param1], data); redraw(); break; } #define updatefriend(fp) redraw();//list_draw(); if(sitem && fp == sitem->data) {ui_drawmain();} #define updategroup(gp) redraw();//list_draw(); if(sitem && gp == sitem->data) {ui_drawmain();} case FRIEND_NAME: { FRIEND *f = &friend[param1]; friend_setname(f, data, param2); updatefriend(f); break; } case FRIEND_STATUS_MESSAGE: { FRIEND *f = &friend[param1]; free(f->status_message); f->status_length = param2; f->status_message = data; updatefriend(f); break; } case FRIEND_STATUS: { FRIEND *f = &friend[param1]; f->status = param2; updatefriend(f); break; } case FRIEND_TYPING: { FRIEND *f = &friend[param1]; friend_set_typing(f, param2); updatefriend(f); break; } case FRIEND_ONLINE: { FRIEND *f = &friend[param1]; f->online = param2; if(!f->online) { friend_set_typing(f, 0); } updatefriend(f); break; } case FRIEND_CALL_STATUS: { /* param1: friend id param2: call id data: integer call status */ FRIEND *f = &friend[param1]; uint8_t status = (size_t)data; if(status == CALL_NONE && (f->calling == CALL_OK || f->calling == CALL_OK_VIDEO)) { toxaudio_postmessage(AUDIO_CALL_END, param2, 0, NULL); if(f->calling == CALL_OK_VIDEO) { toxvideo_postmessage(VIDEO_CALL_END, param2, 0, NULL); } video_end(param1 + 1); } f->calling = status; f->callid = param2; if(status == CALL_OK) { toxaudio_postmessage(AUDIO_CALL_START, param2, 0, NULL); } call_notify(f, status); updatefriend(f); break; } case FRIEND_CALL_VIDEO: { /* param1: friend id param2: call id */ FRIEND *f = &friend[param1]; f->calling = CALL_OK_VIDEO; f->callid = param2; updatefriend(f); toxvideo_postmessage(VIDEO_CALL_START, param2, 0, NULL); toxaudio_postmessage(AUDIO_CALL_START, param2, 0, NULL); f->call_width = 640; f->call_height = 480; video_begin(param1 + 1, f->name, f->name_length, 640, 480); call_notify(f, CALL_OK_VIDEO); break; } case FRIEND_CALL_MEDIACHANGE: { /* param1: friend id param2: call id data: zero = audio, nonzero = audio/video */ FRIEND *f = &friend[param1]; if(!data) { video_end(param1 + 1); } else { f->call_width = 640; f->call_height = 480; video_begin(param1 + 1, f->name, f->name_length, 640, 480); } break; } case FRIEND_CALL_START_VIDEO: { /* param1: friend id param2: call id */ FRIEND *f = &friend[param1]; if(f->calling == CALL_OK) { f->calling = CALL_OK_VIDEO; toxvideo_postmessage(VIDEO_CALL_START, param2, 0, NULL); updatefriend(f); } break; } case FRIEND_CALL_STOP_VIDEO: { /* param1: friend id param2: call id */ FRIEND *f = &friend[param1]; if(f->calling == CALL_OK_VIDEO) { f->calling = CALL_OK; toxvideo_postmessage(VIDEO_CALL_END, param2, 0, NULL); updatefriend(f); } break; } case FRIEND_VIDEO_FRAME: { /* param1: friend id param2: call id data: frame data */ uint16_t *image = data; FRIEND *f = &friend[param1]; _Bool b = (image[0] != f->call_width || image[1] != f->call_height); if(b) { f->call_width = image[0]; f->call_height = image[1]; } video_frame(param1 + 1, (void*)&image[2], image[0], image[1], b); free(image); break; } case PREVIEW_FRAME_NEW: case PREVIEW_FRAME: { if(video_preview) { video_frame(0, data, param1, param2, tox_message_id == PREVIEW_FRAME_NEW); } free(data); break; } case FRIEND_FILE_IN_NEW: case FRIEND_FILE_IN_NEW_INLINE: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->incoming[param2]; _Bool inline_png = (tox_message_id == FRIEND_FILE_IN_NEW_INLINE); MSG_FILE *msg = malloc(sizeof(MSG_FILE)); msg->author = 0; msg->msg_type = MSG_TYPE_FILE; msg->filenumber = param2; msg->status = (inline_png ? FILE_OK : FILE_PENDING); msg->name_length = (ft->name_length > sizeof(msg->name)) ? sizeof(msg->name) : ft->name_length; msg->size = ft->total; msg->progress = 0; msg->speed = 0; msg->inline_png = inline_png; msg->path = NULL; memcpy(msg->name, ft->name, msg->name_length); friend_addmessage(f, msg); ft->chatdata = msg; file_notify(f, msg); updatefriend(f); break; } case FRIEND_FILE_OUT_NEW: case FRIEND_FILE_OUT_NEW_INLINE: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->outgoing[param2]; _Bool inline_png = (tox_message_id == FRIEND_FILE_OUT_NEW_INLINE); MSG_FILE *msg = malloc(sizeof(MSG_FILE)); msg->author = 1; msg->msg_type = MSG_TYPE_FILE; msg->filenumber = param2; msg->status = FILE_PENDING; msg->name_length = (ft->name_length >= sizeof(msg->name)) ? sizeof(msg->name) - 1 : ft->name_length; msg->size = ft->total; msg->progress = 0; msg->speed = 0; msg->inline_png = inline_png; msg->path = NULL; memcpy(msg->name, ft->name, msg->name_length); msg->name[msg->name_length] = 0; friend_addmessage(f, msg); ft->chatdata = msg; updatefriend(f); break; } case FRIEND_FILE_IN_STATUS: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->incoming[param2]; MSG_FILE *msg = ft->chatdata; msg->status = (size_t)data; file_notify(f, msg); updatefriend(f); break; } case FRIEND_FILE_OUT_STATUS: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->outgoing[param2]; MSG_FILE *msg = ft->chatdata; msg->status = (size_t)data; file_notify(f, msg); updatefriend(f); break; } case FRIEND_FILE_IN_DONE: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->incoming[param2]; MSG_FILE *msg = ft->chatdata; msg->status = FILE_DONE; msg->path = data; file_notify(f, msg); updatefriend(f); break; } case FRIEND_FILE_IN_DONE_INLINE: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->incoming[param2]; MSG_FILE *msg = ft->chatdata; msg->status = FILE_DONE; msg->path = data; friend_recvimage(f, data, msg->size); file_notify(f, msg); updatefriend(f); break; } case FRIEND_FILE_OUT_DONE: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->outgoing[param2]; MSG_FILE *msg = ft->chatdata; msg->status = FILE_DONE; msg->path = data; file_notify(f, msg); updatefriend(f); break; } case FRIEND_FILE_IN_PROGRESS: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->incoming[param2]; FILE_PROGRESS *p = data; MSG_FILE *msg = ft->chatdata; msg->progress = p->bytes; msg->speed = p->speed; free(p); updatefriend(f); break; } case FRIEND_FILE_OUT_PROGRESS: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->outgoing[param2]; FILE_PROGRESS *p = data; MSG_FILE *msg = ft->chatdata; msg->progress = p->bytes; msg->speed = p->speed; free(p); updatefriend(f); break; } case GROUP_ADD: { GROUPCHAT *g = &group[param1]; g->name_length = snprintf((char*)g->name, sizeof(g->name), "Groupchat #%u", param1); g->topic_length = sizeof("Drag friends to invite them") - 1; memcpy(g->topic, "Drag friends to invite them", sizeof("Drag friends to invite them") - 1); g->msg.scroll = 1.0; g->type = tox_group_get_type(data, param1); list_addgroup(g); redraw(); break; } case GROUP_MESSAGE: { GROUPCHAT *g = &group[param1]; message_add(&messages_group, data, &g->msg); if(sitem && g == sitem->data) { redraw();//ui_drawmain(); } break; } case GROUP_PEER_DEL: { GROUPCHAT *g = &group[param1]; if (param2 > MAX_GROUP_PEERS) //TODO: dynamic arrays. break; if(g->peername[param2]) { free(g->peername[param2]); g->peername[param2] = NULL; } g->peers--; g->peername[param2] = g->peername[g->peers]; g->peername[g->peers] = NULL; if (g->type == TOX_GROUPCHAT_TYPE_AV) { g->last_recv_audio[param2] = g->last_recv_audio[g->peers]; g->last_recv_audio[g->peers] = 0; group_av_peer_remove(g, param2); g->source[param2] = g->source[g->peers]; } if (g->peers == g->our_peer_number) { g->our_peer_number = param2; } g->topic_length = snprintf((char*)g->topic, sizeof(g->topic), "%u users in chat", g->peers); updategroup(g); break; } case GROUP_PEER_ADD: case GROUP_PEER_NAME: { GROUPCHAT *g = &group[param1]; if (param2 > MAX_GROUP_PEERS) //TODO: dynamic arrays. break; if(g->peername[param2]) { free(g->peername[param2]); } if(tox_message_id == GROUP_PEER_ADD) { if (g->type == TOX_GROUPCHAT_TYPE_AV) { group_av_peer_add(g, param2); } if (tox_group_peernumber_is_ours(data, param1, param2)) { g->our_peer_number = param2; } uint8_t *n = malloc(10); n[0] = 9; memcpy(n + 1, "<unknown>", 9); data = n; g->peers++; } g->peername[param2] = data; g->topic_length = snprintf((char*)g->topic, sizeof(g->topic), "%u users in chat", g->peers); updategroup(g); break; } case GROUP_TITLE: { GROUPCHAT *g = &group[param1]; if (param2 > sizeof(g->name)) { memcpy(g->name, data, sizeof(g->name)); g->name_length = sizeof(g->name); } else { memcpy(g->name, data, param2); g->name_length = param2; } free(data); updategroup(g); break; } case GROUP_AUDIO_START: { GROUPCHAT *g = &group[param1]; if (g->type == TOX_GROUPCHAT_TYPE_AV) { g->audio_calling = 1; toxaudio_postmessage(GROUP_AUDIO_CALL_START, param1, 0, NULL); updategroup(g); } break; } case GROUP_AUDIO_END: { GROUPCHAT *g = &group[param1]; if (g->type == TOX_GROUPCHAT_TYPE_AV) { g->audio_calling = 0; toxaudio_postmessage(GROUP_AUDIO_CALL_END, param1, 0, NULL); updategroup(g); } break; } case GROUP_UPDATE: { GROUPCHAT *g = &group[param1]; updategroup(g); break; } }
int main(void) { //*uart_chan0_interruptenable |= INTERRUPTENABLE_ERBFI; //uint16_t* blip = _binary_blip_start; //for (int i = 0; i < sizeof(_binary_blip_start) / 2; i++) { // *(sound_bank_0 + i) = *blip++; //} //*sound_channel_0_samplelength = sizeof(_binary_blip_start); //*sound_channel_master_config = 0xFFFF; //*sound_channel_master_volume = 0xFF99; //*sound_channel_0_volume = 0xFF22; //*sound_channel_0_config = 0xF9FF; FATFS fs; FRESULT result; result = pf_mount(&fs); util_printffresult(result); util_printfat(&fs); result = pf_open("test.txt"); util_printffresult(result); char buf[64]; uint16_t len; pf_read(buf, 63, &len); printf("read from file: %s\n", buf); image_loadimagefromfile(&fs, &pai, "pai.bz", true); image_loadimagefromfile(&fs, &ballimage, "ball.be", false); newball(&ball1, 0, 0, &ballimage); newball(&ball2, 50, 0, &ballimage); initvideo(); machine_setinterruptmask(0); while (1) { if (fbready) continue; static uint16_t lastframe = 0; static uint16_t thisframe; uint16_t vidflags = video_register_flags; uint8_t port0 = input_port0; thisframe = video_register_frame; updateball(&ball1, thisframe, lastframe); updateball(&ball2, thisframe, lastframe); ballcollision(&ball1, &ball2); video_begin(); video_clear(0xFFFF); video_blitimage_nocopy(pai.width, pai.height, 30, 30, pai.data); sprite_draw(ball1.sprite); sprite_draw(ball2.sprite); video_drawline(&vect); video_gputs("Hello World!", _binary_fontrom_start, 1, 1); lastframe = thisframe; video_commit(); //video_flip(); fbready = true; } printf("Shouldn't have got here!"); while (1) { } return 0; }